JDBC事务

事务用于提供数据完整性、正确的应用程序语义和并发访问的数据一致性。所有遵循JDBC规范的驱动程序都需要提供事务支持。

JDBC API中的事务管理符合SQL:2003规范,主要包含下面几个概念:

  • 自动提交模式
  • 事务隔离级别
  • 保存点

事务隔离级别

  • TRANSACTION_NONE:表示驱动不支持事务,这意味着它是不兼容JDBC规范的驱动程序。
  • TRANSACTION_READ_UNCOMMITTED:允许事务读取未提交更改的数据,这意味着可能会出现脏读、不可重复读、幻读等现象。
  • TRANSACTION_READ_COMMITTED:表示在事务中进行的任何数据更改,在提交之前对其他事务是不可见的。这样可以防止脏读,但是不能解决不可重复读和幻读的问题。
  • TRANSACTION_REPEATABLE_READ:该事务隔离级别能够解决脏读和不可重复读问题,但是不能解决幻读问题。
  • TRANSACTION_SERIALIZABLE:该事务隔离级别下,所有事务串行执行,能够有效解决脏读、不可重复读和幻读问题,但是并发效率较低。

Connection对象的默认事务级别由JDBC驱动程序指定。通常它是底层数据源支持的默认事务隔离级别。Connection接口中提供了一个setTransactionIsolation()方法,允许JDBC客户端设置Connection对象的事务隔离级别。新设置的事务隔离级别会在之后的会话中生效。在一个事务中调用setTransactionIsolation()方法是否对当前事务有效取决于具体的驱动实现。JDBC规范建议在调用setTransactionIsolation()方法后,下一个新的事务开始生效。另外,JDBC驱动可能不完全支持除TRANSACTION_NONE之外的4个事务级别。

调用Connection对象的setTransactionIsolation()方法时,如果参数是驱动不支持的事务隔离级别,则驱动程序应该使用更高的级别代替该参数指定的级别,如果驱动不支持更高的级别,就会抛出SQLException异常,可以调用DatabaseMetaData对象的supportsTransactionIsolationLevel()方法判断是否支持某一事务隔离级别。

事务中的保存点

保存点通过在事务中标记一个中间的点来对事务进行更细粒度的控制,一旦设置保存点,事务就可以回滚到保存点,而不影响保存点之前的操作。DatabaseMetaData接口提供了supportsSavepoints()方法,用于判断JDBC驱动是否支持保存点。

Connection接口中提供了setSavepoint()方法用于在当前事务中设置保存点,如果setSavepoint()方法在事务外调用,则调用该方法后会在setSavepoint()方法调用处开启一个新的事务。setSavepoint()方法的返回值是一个Savepoint对象,该对象可作为Connection对象rollback()方法的参数,用于回滚到对应的保存点。下面是将事务回滚到保存点的一个案例,代码如下:

		@Test
    public void testSavePoint() {
        try {
            Class.forName("org.hsqldb.jdbcDriver");
            // 获取Connection对象
            Connection conn = DriverManager.getConnection("jdbc:hsqldb:mem:mybatis",
                    "sa", "");
            String sql1 = "insert into user(create_time, name, password, phone, nick_name) " +
                    "values('2010-10-24 10:20:30','User1','test','18700001111','User1')";
            String sql2 = "insert into user(create_time, name, password, phone, nick_name) " +
                    "values('2010-10-24 10:20:30','User2','test','18700001111','User2')";
            conn.setAutoCommit(false);
            Statement stmt = conn.createStatement();
            stmt.executeUpdate(sql1);
            // 创建保存点
            Savepoint savepoint = conn.setSavepoint("SP1");
            stmt.executeUpdate(sql2);
            // 回滚到保存点
            conn.rollback(savepoint);
            conn.commit();
            ResultSet rs  = conn.createStatement().executeQuery("select * from user ");
            DbUtils.dumpRS(rs);
            IOUtils.closeQuietly(stmt);
            IOUtils.closeQuietly(conn);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

注意:摘要于《mybatis3源码深度解析》

posted @ 2023-04-03 11:22  围观的小妖g  阅读(43)  评论(0)    收藏  举报