欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDBC的事务初探 博客分类: Database JDBCSQLSQL ServerMySQLSpring 

程序员文章站 2024-02-19 20:54:40
...

很久没有更新Blog,有点惭愧啊,呵呵,其实我一直在懵懵懂懂的学习事务处理。Spring把这一切封装的很好了,以至于我现在都无法正常写出一个像样的JDBC事务处理的程序,如果让我用JDBC写语句,还是有很多ASP的影子。无意中买了10月的《程序员》杂志,没想到里面讲了SQL Server的事务处理,我耐着性子看完了,于是我想把它转换成实际的Java代码。呵呵,言归正传,开始我们今天的旅行吧。

首先,我的平台是WindowsXP2+JDK1.5+myeclispe6.0+mysql5.037。这个环境配置可能与大家不一样,请注意一下。先建一个数据库,我用的是MySQL自带的test,在里面随便建立了一个表格,结构如下,大家可以随便建立,不必过于在意,因为是初探,所以开始不会有很复杂的内容,而且东西也是越简单越好,呵呵。

sql 代码
  1. DROP TABLE IF EXISTS `tbl_tran`;   
  2. CREATE TABLE `tbl_tran` (   
  3.   `id` int(10) unsigned NOT NULL auto_increment,   
  4.   `namevarchar(45) NOT NULL,   
  5.   `age` int(10) unsigned NOT NULL,   
  6.   `gender` char(1) NOT NULL,   
  7.   `memo` text,   
  8.   PRIMARY KEY  (`id`)   
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  

 

建立好了表,可以往里加入一个测试数据比如:

sql 代码
  1. INSERT INTO `tbl_tran` VALUES (1,'leo',0,'M','hello leo');  

一切都准备好了。开始写测试代码啦。

java 代码
  1. package com.leo.tran;   
  2.   
  3. import java.sql.Connection;   
  4. import java.sql.ResultSet;   
  5. import java.sql.SQLException;   
  6. import java.sql.Statement;   
  7.   
  8. import com.leo.jdbc.DBConnection;   
  9.   
  10. public class TranJDBC1 {   
  11.   
  12.     private static Connection conn;   
  13.     private static Connection conn_two;   
  14.   
  15.     // 要测试的某条记录   
  16.     private static String testName = "leo";   
  17.   
  18.     // 要测试的这条记录更新的一个字段   
  19.     private static int testAge = 23;   
  20.   
  21.     /**  
  22.      * 初始化两个连接,不使用单例  
  23.      */  
  24.     static {   
  25.         conn = DBConnection.getConnection();   
  26.         conn_two = DBConnection.getConnection();   
  27.         try {   
  28.             conn_two.setAutoCommit(false);   
  29.         } catch (SQLException e) {   
  30.             e.printStackTrace();   
  31.         }   
  32.     }   
  33.   
  34.     /**  
  35.      * 默认的事物处理级别为4 也就是:TRANSACTION_REPEATABLE_READ,支持可重复读  
  36.      *   
  37.      * @param conn  
  38.      * @return  
  39.      * @throws SQLException  
  40.      */  
  41.     public static int getDefaultTransactionIsolation(Connection conn)   
  42.             throws SQLException {   
  43.         return conn.getTransactionIsolation();   
  44.     }   
  45.   
  46.     /**  
  47.      * 更新测试记录  
  48.      */  
  49.     public static void updateTable(int age) {   
  50.         Statement stmt = null;   
  51.         try {   
  52.             stmt = conn_two.createStatement();   
  53.             stmt.executeUpdate("update tbl_tran set age = " + age   
  54.                     + " where name = '" + testName + "'");   
  55.             System.out.println("[数据库开始更新中..............]");   
  56.         } catch (SQLException e) {   
  57.             try {   
  58.                 conn_two.close();   
  59.             } catch (SQLException e1) {   
  60.                 e1.printStackTrace();   
  61.             }   
  62.         }   
  63.     }   
  64.   
  65.     /**  
  66.      * 查询测试记录信息  
  67.      */  
  68.     public static void selectTable() {   
  69.         Statement stmt = null;   
  70.         try {   
  71.             stmt = conn.createStatement();   
  72.             String sql = "select * from tbl_tran where name = '" + testName   
  73.                     + "'";   
  74.             ResultSet rs = stmt.executeQuery(sql);   
  75.             while (rs.next()) {   
  76.                 System.out   
  77.                         .println("===========================打印输出开始===============================");   
  78.                 System.out.println("[ID为: " + rs.getInt("id") + "]");   
  79.                 System.out.println("[Name为: " + rs.getString("name") + "]");   
  80.                 System.out.println("[age为: " + rs.getString("age") + "]");   
  81.                 System.out.println("[gender为: " + rs.getString("gender") + "]");   
  82.                 System.out.println("[memo为: " + rs.getString("memo") + "]");   
  83.                 System.out   
  84.                         .println("===========================打印输出结束===============================");   
  85.             }   
  86.         } catch (SQLException e) {   
  87.             try {   
  88.                 conn.close();   
  89.             } catch (SQLException e1) {   
  90.                 e1.printStackTrace();   
  91.             }   
  92.         }   
  93.     }   
  94.   
  95.     /**  
  96.      * 使用默认的自动提交的Connection测试  
  97.      * @throws SQLException  
  98.      */  
  99.     public static void testTransaction() throws SQLException {   
  100.         System.out.println("[查看需要测试的记录原始信息.........]");   
  101.         System.out.println("[未更新前的详细信息.........]");   
  102.         selectTable();   
  103.         System.out.println("[为了测试先把查询的conn的事务设置成提交读.........]");   
  104.         // Transaction isolation level NONE not supported by MySQL   
  105.         conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);   
  106.         // 设置conn_two为默认提交   
  107.         conn_two.setAutoCommit(true);   
  108.         updateTable(testAge);   
  109.         System.out.println("[更新后,但事务自动提交后记录的详细信息.........]");   
  110.         selectTable();   
  111.     }   
  112.   
  113.     /**  
  114.      * 关闭默认自动提交的Connection测试  
  115.      * @throws SQLException  
  116.      */  
  117.     public static void testTransaction2() throws SQLException {   
  118.         System.out.println("[查看需要更新的记录信息.........]");   
  119.         System.out.println("[未更新前的详细信息.........]");   
  120.         selectTable();   
  121.         System.out.println("[为了测试先把查询的conn的事务设置成提交读.........]");   
  122.         // 注意:Transaction isolation level NONE not supported by MySQL   
  123.         conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);   
  124.         updateTable(testAge);   
  125.         System.out.println("[更新后,但事务尚未提交时记录的详细信息.........]");   
  126.         selectTable();   
  127.         // 提交那个更新的Connection,然后再查询数据库   
  128.         conn_two.commit();   
  129.         System.out.println("[更新后,但事务提交后记录的详细信息.........]");   
  130.         selectTable();   
  131.   
  132.     }   
  133.   
  134.     public static void main(String[] args) throws SQLException {   
  135.         System.out.println("[先看看Connection默认事务处理级别为: "  
  136.                 + getDefaultTransactionIsolation(conn) + " ]");   
  137.         System.out.println();   
  138.         testTransaction();   
  139.   
  140.     }   
  141.   
  142. }  

条码很简单,就是两个方法:

1.testTransaction():大家在使用Connection的时候,常常容易使用默认的连接,而这个连接是默认提交的,不具备事务处理的能力,所以在测试中,即使你已经设置了另一个Conn的隔离级别,但仍然不起作用,呵呵,我在刚开始编程ASP的时候,要处理关联表,不知道事务的概念,常常是一个表有数据了,另一个表出问题了,或者是插入一半数据了,然后手工改,慢慢接触了Java,使用了Spring,才知道事务的概念很重要。

2.testTransaction2():是正确的使用方法。一个连接在访问一条记录,另一个连接却想更新这条记录,那么应该看到什么样的结果呢?这个时候,隔离级别就起作用了,这里用的是READ_COMMITED,即提交读,也就是说没有提交过的记录是看不到的。只有更新的那个Conn_two提交了,或者是回滚了,也就是说Conn_two的事务结束了,才可以看到最后的结果。打印的结果是:

 

java 代码
  1. [数据库已打开...........................]   
  2. [数据库已打开...........................]   
  3. [先看看Connection默认事务处理级别为: 4 ]   
  4.   
  5. [查看需要更新的记录信息.........]   
  6. [未更新前的详细信息.........]   
  7. ===========================打印输出开始===============================   
  8. [ID为: 1]   
  9. [Name为: leo]   
  10. [age为: 0]   
  11. [gender为: M]   
  12. [memo为: hello leo]   
  13. ===========================打印输出结束===============================   
  14. [为了测试先把查询的conn的事务设置成提交读.........]   
  15. [数据库开始更新中..............]   
  16. [更新后,但事务尚未提交时记录的详细信息.........]   
  17. ===========================打印输出开始===============================   
  18. [ID为: 1]   
  19. [Name为: leo]   
  20. [age为: 0]   
  21. [gender为: M]   
  22. [memo为: hello leo]   
  23. ===========================打印输出结束===============================   
  24. [更新后,但事务提交后记录的详细信息.........]   
  25. ===========================打印输出开始===============================   
  26. [ID为: 1]   
  27. [Name为: leo]   
  28. [age为: 23]   
  29. [gender为: M]   
  30. [memo为: hello leo]   
  31. ===========================打印输出结束===============================   

 

我的main()方法,测试的是testTransaction2(),而testTransaction()大家也可测试一下,了解有时候默认的配置并不是最合适的选择。这个主题还会继续补充的,今天先到这里吧。