MyBatis 事务源码分析

先来看看在JAVA事务的相关技术,在JAVA中有两类事务,JDBC事务和JTA事务,如果是JDBC类型的事务,则是由Connection类来控制的。如果创建一个Connection对象时,没有显示调用

setTransactionIsolation(int level) 方法,则Connection使用当前数据库默认的事务隔离级别,数据库的默认事务隔离级别可以通过相应的SQL语句进行查询,例如在Mysql数据库下可使用 select @@tx_isolation;语句查看当前数据库的事务隔离级别。

JDBCConnection类针对事务的隔离性定义了五个隔离级别。

Connection.TRANSACTION_NONE

Connection.TRANSACTION_READ_COMMITTED

Connection.TRANSACTION_READ_UNCOMMITTED

Connection.TRANSACTION_REPEATABLE_READ

Connection.TRANSACTION_SERIALIZABLE

在mybatis中,有一个事务管理器的配置,其中type属性可以配置事务的类型,提供了JDBCMANAGED的配置属性,这就说明在mybatis中事务的管理方式有两个事务管理器的实现,都是针对JDBC事务的事务管理器(非JTA事务),分别是:

  org.apache.ibatis.transaction.jdbc.JdbcTransaction

  org.apache.ibatis.transaction.managed.ManagedTransaction

这两个类都实现了org.apache.ibatis.transaction.Transaction接口,Transaction接口定义了如下方法:

   Connection getConnection() throws SQLException;
   void commit() throws SQLException;
   void rollback() throws SQLException;
   void close() throws SQLException;

通过这些方法可以看出这个接口实际是对Connection类进行了包装,包括了Connection的创建、提交、回滚、关闭动作。并且,其中ManagedTransaction类的commit方法和rollback方法中没有做任何事,也就是说这个类是不控制事务的提交和回滚的,而交由外部容器去管理事务的提交与回滚,外部容器(可以是Spring 容器或EJB容器)通过声明式事务的方式进行管事。

mybatis中,通过一个Enumorg.apache.ibatis.session.TransactionIsolationLevel

来定义了事务的隔离级别:

复制代码
public enum TransactionIsolationLevel {
  NONE(Connection.TRANSACTION_NONE),
  READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
  READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
  REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
  SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);

  private final int level;

  private TransactionIsolationLevel(int level) {
    this.level = level;
  }

  public int getLevel() {
    return level;
  }
}
复制代码

TransactionIsolationLevel类中定义的事务隔离级别其实就是引用了Connection类中的事务隔离级别,下面分别对这几种隔离级别进行说明: 

TRANSACTION_NONE:表示不支持事务的常量

TRANSACTION_READ_UNCOMMITTED:表示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量

TRANSACTION_READ_COMMITTED:不可重复读和虚读可以发生

TRANSACTION_REPEATABLE_READ:虚读可以发生

TRANSACTION_SERIALIZABLE:指示不可以发生脏读、不可重复读和虚读的常量。

再来理解下什么是脏读、不能重复读、虚读(又叫幻读)

脏读:如果一个事务对数据进行了更新,但事务还没有提交,另一个事务就可以“看到”该事务没有提交的更新结果。这样造成的问题是,如果第一个事务回滚,那么第二个事务在此之前所“看到”的数据就是一笔脏数据。

不可重复读:指同个事务在整个事务过程中对同一笔数据进行读取,每次读取结果都不同。如果事务1在事务2的更新操作之前读取一次数据,在事务2的更新操作之后再读取同一笔数据一次,两次结果是不同的。所以TRANSACTION_READ_COMMITTED是无法避免不可重复读和虚读。

幻读:指同样一个查询在整个事务过程中多次执行后,查询所得的结果集是不一样的。幻读针对的是多笔记录。

最后再总结下:mybatis只是对JDBC事务提供了事务管理器的封装,如果想在mybatis中使用JTA事务,需要我们自行实现org.apache.ibatis.transaction.Transaction接口,对此Spring框架提供了解决方案,可能通过mybatis+spring+atomikos的整合来完成。或者采用EJB容器也可以提供JTA事务的支持。

posted @ 2017-02-26 11:27  刘二雄  阅读(448)  评论(0编辑  收藏  举报