JDBC的事务初探 博客分类: Database JDBCSQLSQL ServerMySQLSpring
很久没有更新Blog,有点惭愧啊,呵呵,其实我一直在懵懵懂懂的学习事务处理。Spring把这一切封装的很好了,以至于我现在都无法正常写出一个像样的JDBC事务处理的程序,如果让我用JDBC写语句,还是有很多ASP的影子。无意中买了10月的《程序员》杂志,没想到里面讲了SQL Server的事务处理,我耐着性子看完了,于是我想把它转换成实际的Java代码。呵呵,言归正传,开始我们今天的旅行吧。
首先,我的平台是WindowsXP2+JDK1.5+myeclispe6.0+mysql5.037。这个环境配置可能与大家不一样,请注意一下。先建一个数据库,我用的是MySQL自带的test,在里面随便建立了一个表格,结构如下,大家可以随便建立,不必过于在意,因为是初探,所以开始不会有很复杂的内容,而且东西也是越简单越好,呵呵。
- DROP TABLE IF EXISTS `tbl_tran`;
- CREATE TABLE `tbl_tran` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `name` varchar(45) NOT NULL,
- `age` int(10) unsigned NOT NULL,
- `gender` char(1) NOT NULL,
- `memo` text,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
建立好了表,可以往里加入一个测试数据比如:
- INSERT INTO `tbl_tran` VALUES (1,'leo',0,'M','hello leo');
一切都准备好了。开始写测试代码啦。
- package com.leo.tran;
- import java.sql.Connection;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.sql.Statement;
- import com.leo.jdbc.DBConnection;
- public class TranJDBC1 {
- private static Connection conn;
- private static Connection conn_two;
- // 要测试的某条记录
- private static String testName = "leo";
- // 要测试的这条记录更新的一个字段
- private static int testAge = 23;
- /**
- * 初始化两个连接,不使用单例
- */
- static {
- conn = DBConnection.getConnection();
- conn_two = DBConnection.getConnection();
- try {
- conn_two.setAutoCommit(false);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- /**
- * 默认的事物处理级别为4 也就是:TRANSACTION_REPEATABLE_READ,支持可重复读
- *
- * @param conn
- * @return
- * @throws SQLException
- */
- public static int getDefaultTransactionIsolation(Connection conn)
- throws SQLException {
- return conn.getTransactionIsolation();
- }
- /**
- * 更新测试记录
- */
- public static void updateTable(int age) {
- Statement stmt = null;
- try {
- stmt = conn_two.createStatement();
- stmt.executeUpdate("update tbl_tran set age = " + age
- + " where name = '" + testName + "'");
- System.out.println("[数据库开始更新中..............]");
- } catch (SQLException e) {
- try {
- conn_two.close();
- } catch (SQLException e1) {
- e1.printStackTrace();
- }
- }
- }
- /**
- * 查询测试记录信息
- */
- public static void selectTable() {
- Statement stmt = null;
- try {
- stmt = conn.createStatement();
- String sql = "select * from tbl_tran where name = '" + testName
- + "'";
- ResultSet rs = stmt.executeQuery(sql);
- while (rs.next()) {
- System.out
- .println("===========================打印输出开始===============================");
- System.out.println("[ID为: " + rs.getInt("id") + "]");
- System.out.println("[Name为: " + rs.getString("name") + "]");
- System.out.println("[age为: " + rs.getString("age") + "]");
- System.out.println("[gender为: " + rs.getString("gender") + "]");
- System.out.println("[memo为: " + rs.getString("memo") + "]");
- System.out
- .println("===========================打印输出结束===============================");
- }
- } catch (SQLException e) {
- try {
- conn.close();
- } catch (SQLException e1) {
- e1.printStackTrace();
- }
- }
- }
- /**
- * 使用默认的自动提交的Connection测试
- * @throws SQLException
- */
- public static void testTransaction() throws SQLException {
- System.out.println("[查看需要测试的记录原始信息.........]");
- System.out.println("[未更新前的详细信息.........]");
- selectTable();
- System.out.println("[为了测试先把查询的conn的事务设置成提交读.........]");
- // Transaction isolation level NONE not supported by MySQL
- conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
- // 设置conn_two为默认提交
- conn_two.setAutoCommit(true);
- updateTable(testAge);
- System.out.println("[更新后,但事务自动提交后记录的详细信息.........]");
- selectTable();
- }
- /**
- * 关闭默认自动提交的Connection测试
- * @throws SQLException
- */
- public static void testTransaction2() throws SQLException {
- System.out.println("[查看需要更新的记录信息.........]");
- System.out.println("[未更新前的详细信息.........]");
- selectTable();
- System.out.println("[为了测试先把查询的conn的事务设置成提交读.........]");
- // 注意:Transaction isolation level NONE not supported by MySQL
- conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
- updateTable(testAge);
- System.out.println("[更新后,但事务尚未提交时记录的详细信息.........]");
- selectTable();
- // 提交那个更新的Connection,然后再查询数据库
- conn_two.commit();
- System.out.println("[更新后,但事务提交后记录的详细信息.........]");
- selectTable();
- }
- public static void main(String[] args) throws SQLException {
- System.out.println("[先看看Connection默认事务处理级别为: "
- + getDefaultTransactionIsolation(conn) + " ]");
- System.out.println();
- testTransaction();
- }
- }
条码很简单,就是两个方法:
1.testTransaction():大家在使用Connection的时候,常常容易使用默认的连接,而这个连接是默认提交的,不具备事务处理的能力,所以在测试中,即使你已经设置了另一个Conn的隔离级别,但仍然不起作用,呵呵,我在刚开始编程ASP的时候,要处理关联表,不知道事务的概念,常常是一个表有数据了,另一个表出问题了,或者是插入一半数据了,然后手工改,慢慢接触了Java,使用了Spring,才知道事务的概念很重要。
2.testTransaction2():是正确的使用方法。一个连接在访问一条记录,另一个连接却想更新这条记录,那么应该看到什么样的结果呢?这个时候,隔离级别就起作用了,这里用的是READ_COMMITED,即提交读,也就是说没有提交过的记录是看不到的。只有更新的那个Conn_two提交了,或者是回滚了,也就是说Conn_two的事务结束了,才可以看到最后的结果。打印的结果是:
- [数据库已打开...........................]
- [数据库已打开...........................]
- [先看看Connection默认事务处理级别为: 4 ]
- [查看需要更新的记录信息.........]
- [未更新前的详细信息.........]
- ===========================打印输出开始===============================
- [ID为: 1]
- [Name为: leo]
- [age为: 0]
- [gender为: M]
- [memo为: hello leo]
- ===========================打印输出结束===============================
- [为了测试先把查询的conn的事务设置成提交读.........]
- [数据库开始更新中..............]
- [更新后,但事务尚未提交时记录的详细信息.........]
- ===========================打印输出开始===============================
- [ID为: 1]
- [Name为: leo]
- [age为: 0]
- [gender为: M]
- [memo为: hello leo]
- ===========================打印输出结束===============================
- [更新后,但事务提交后记录的详细信息.........]
- ===========================打印输出开始===============================
- [ID为: 1]
- [Name为: leo]
- [age为: 23]
- [gender为: M]
- [memo为: hello leo]
- ===========================打印输出结束===============================
我的main()方法,测试的是testTransaction2(),而testTransaction()大家也可测试一下,了解有时候默认的配置并不是最合适的选择。这个主题还会继续补充的,今天先到这里吧。
下一篇: java实现学生选课系统