为了账号安全,请及时绑定邮箱和手机立即绑定

Mybatis事务管理

标签:
Java

1、Mybatis事务

1.1、事务管理方式

Mybatis中的事务管理方式有两种:

1、JDBC的事务管理机制,即使用JDBC事务管理机制进行事务管理

2、MANAGED的事务管理机制,Mybatis没有实现对事务的管理,而是通过容器来实现对事务的管理

其中,Mybatis提供了事务的接口:Transaction,其代码如下:

public interface Transaction {  /**
   * Retrieve inner database connection
   * @return DataBase connection
   * @throws SQLException
   */
  //获得数据库连接
  Connection getConnection() throws SQLException;  /**
   * Commit inner database connection.
   * @throws SQLException
   */
  //提交
  void commit() throws SQLException;  /**
   * Rollback inner database connection.
   * @throws SQLException
   */
  //回滚
  void rollback() throws SQLException;  /**
   * Close inner database connection.
   * @throws SQLException
   */
  //连接关闭
  void close() throws SQLException;  /**
   * Get transaction timeout if set
   * @throws SQLException
   */
  //获取事务timeout
  Integer getTimeout() throws SQLException;
  
}

Transaction有两个实现类:JdbcTransaction和ManagedTransaction,分别对应两种事务管理方式。

JdbcTransaction的代码如下:

public class JdbcTransaction implements Transaction {  private static final Log log = LogFactory.getLog(JdbcTransaction.class);  //数据连接
  protected Connection connection;  //数据源
  protected DataSource dataSource;  //事务等级
  protected TransactionIsolationLevel level;  //事务提交
  protected boolean autoCommmit;  public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
    dataSource = ds;
    level = desiredLevel;
    autoCommmit = desiredAutoCommit;
  }  public JdbcTransaction(Connection connection) {    this.connection = connection;
  }  @Override
  public Connection getConnection() throws SQLException {    if (connection == null) {
      openConnection();
    }    return connection;
  }  @Override
  public void commit() throws SQLException {    if (connection != null && !connection.getAutoCommit()) {      if (log.isDebugEnabled()) {
        log.debug("Committing JDBC Connection [" + connection + "]");
      }
      connection.commit();
    }
  }  @Override
  public void rollback() throws SQLException {    if (connection != null && !connection.getAutoCommit()) {      if (log.isDebugEnabled()) {
        log.debug("Rolling back JDBC Connection [" + connection + "]");
      }
      connection.rollback();
    }
  }  @Override
  public void close() throws SQLException {    if (connection != null) {
      resetAutoCommit();      if (log.isDebugEnabled()) {
        log.debug("Closing JDBC Connection [" + connection + "]");
      }
      connection.close();
    }
  }  protected void setDesiredAutoCommit(boolean desiredAutoCommit) {    try {      //事务提交状态不一致时修改
      if (connection.getAutoCommit() != desiredAutoCommit) {        if (log.isDebugEnabled()) {
          log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
        }
        connection.setAutoCommit(desiredAutoCommit);
      }
    } catch (SQLException e) {      // Only a very poorly implemented driver would fail here,
      // and there's not much we can do about that.
      throw new TransactionException("Error configuring AutoCommit.  "
          + "Your driver may not support getAutoCommit() or setAutoCommit(). "
          + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);
    }
  }  protected void resetAutoCommit() {    try {      if (!connection.getAutoCommit()) {        if (log.isDebugEnabled()) {
          log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
        }
        connection.setAutoCommit(true);
      }
    } catch (SQLException e) {      if (log.isDebugEnabled()) {
        log.debug("Error resetting autocommit to true "
          + "before closing the connection.  Cause: " + e);
      }
    }
  }  protected void openConnection() throws SQLException {    if (log.isDebugEnabled()) {
      log.debug("Opening JDBC Connection");
    }    //从数据源中获得连接
    connection = dataSource.getConnection();    if (level != null) {
      connection.setTransactionIsolation(level.getLevel());
    }
    setDesiredAutoCommit(autoCommmit);
  }  @Override
  public Integer getTimeout() throws SQLException {    return null;
  }
}

JdbcTransaction通过使用jdbc提供的方式来管理事务,通过Connection提供的事务管理方法来进行事务管理,只是将JDBC的事务管理进行了封装。

ManagedTransaction实现类是通过容器来进行事务管理,所有它对事务提交和回滚并不会做任何操作。其代码如下:

public class ManagedTransaction implements Transaction {  private static final Log log = LogFactory.getLog(ManagedTransaction.class);  private DataSource dataSource;  private TransactionIsolationLevel level;  private Connection connection;  private final boolean closeConnection;  public ManagedTransaction(Connection connection, boolean closeConnection) {    this.connection = connection;    this.closeConnection = closeConnection;
  }  public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) {    this.dataSource = ds;    this.level = level;    this.closeConnection = closeConnection;
  }  @Override
  public Connection getConnection() throws SQLException {    if (this.connection == null) {
      openConnection();
    }    return this.connection;
  }  @Override
  public void commit() throws SQLException {    // Does nothing
  }  @Override
  public void rollback() throws SQLException {    // Does nothing
  }  @Override
  public void close() throws SQLException {    if (this.closeConnection && this.connection != null) {      if (log.isDebugEnabled()) {
        log.debug("Closing JDBC Connection [" + this.connection + "]");
      }      this.connection.close();
    }
  }  protected void openConnection() throws SQLException {    if (log.isDebugEnabled()) {
      log.debug("Opening JDBC Connection");
    }    this.connection = this.dataSource.getConnection();    if (this.level != null) {      this.connection.setTransactionIsolation(this.level.getLevel());
    }
  }  @Override
  public Integer getTimeout() throws SQLException {    return null;
  }

}

此外,当Mybatis与Spring一起使用时,Spring会提供一个Transaction的实现类SpringManagedTransaction进行事务管理,这会在后面的Spring源码中说到。

可参考:https://blog.csdn.net/qq924862077/article/details/525997851.2

1.2、事务配置方式

Mybatis的事务管理方式的配置是在核心配置文件中进行的,它是在configuration标签下的environments中与数据源一起配置的,可以配置多个,如下所示:

 <environments default="development">
    <environment id="development">
      //配置事务管理方式      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
      </dataSource>
    </environment></environments>

2、事务隔离级别

在上面的源码中,我们看到TransactionIsolationLevel—事务隔离级别,Mybaais中定义了五种隔离级别,代码如下所示:

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;
  }
}

其中四种是一般数据库的事务隔离级别,从高到底以此为:Read uncommitted(读未提交)、Read committed(读已提交)、Repeatable read(可重复读)、Serializable(可串行化),这几个级别主要用于解决脏读、不可重复读、幻读等问题,其总结如下表:

级别脏读不可重复读幻读说明
Read uncommittedtruetruetrue一个更新语句没有提交,但是别的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。
Read committedfalsetruetrue语句提交以后即执行了COMMIT以后别的事务就能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别,可防止脏读。
Repeatable readfalsefalsetrue同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。
Serializablefalsefalsefalse事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

注:true表示出现,false表示不出现

参考自:https://blog.csdn.net/qq924862077/article/details/52599961

Mybatis添加的隔离级别NONE,可在DefaultSqlSessionFactory中创建SqlSession时,设置数据库的事务隔离级别,以及通过设置autoCommit来设置事务的提交方式。代码参见DefaultSqlSessionFactory,示例代码如下:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)

3、事务工厂

此外,在Mybatis中还提供了事务工厂:TransactionFactory,代码如下所示:

public interface TransactionFactory {  //配置工厂属性
  void setProperties(Properties props);  //通过Connection获取事务
  Transaction newTransaction(Connection conn);  
  //通过数据库,事务等级,是否自动提交创建事务
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

}

类似的,TransactionFactory也有两个实现类:JdbcTransactionFactory和ManagedTransactionFactory

JdbcTransactionFactory代码如下:

public class JdbcTransactionFactory implements TransactionFactory {  @Override
  public void setProperties(Properties props) {
  }  @Override
  public Transaction newTransaction(Connection conn) {    return new JdbcTransaction(conn);
  }  @Override
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {    return new JdbcTransaction(ds, level, autoCommit);
  }
}

ManagedTransactionFactory代码如下:

public class ManagedTransactionFactory implements TransactionFactory {  private boolean closeConnection = true;  @Override
  public void setProperties(Properties props) {    if (props != null) {
      String closeConnectionProperty = props.getProperty("closeConnection");      if (closeConnectionProperty != null) {
        closeConnection = Boolean.valueOf(closeConnectionProperty);
      }
    }
  }  @Override
  public Transaction newTransaction(Connection conn) {    return new ManagedTransaction(conn, closeConnection);
  }  @Override
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {    return new ManagedTransaction(ds, level, closeConnection);
  }
}

作者:紫焱

出处:https://www.cnblogs.com/liuyi6/p/10159426.html  

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消