Mybatis事务管理机制

  • 我们在mybatis入门程序中可以发现,在编写完sql语句后,我们必须手动提交事务,否则数据库表并不会更新该数据

  • 在mybatis-config.xml文件中可通过如下配置进行事务管理

    • <transactionManager type="JDBC"/>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45

      * type属性有两种value

      * JDBC(jdbc)
      * MANAGED(managed)

      * 当value是jdbc时,表示MyBatis框架自己管理事务,底层采用的是原生的jdbc机制:在执行sql语句之前开启事务:conn.setAutoCommit("false");在执行sqlSession.commit();时底层执行conn.commit();

      * ```java
      SqlSession sqlSession = sqlSessionFactory.openSession();
      //该语句的底层源码分析
      //当程序执行该语句时,底层会执行
      public SqlSession openSession() {
      return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
      }
      /* public SqlSession openSession(boolean autoCommit) {
      return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
      }*/
      //也就是说它会调用另一个openSessionFromDataSource方法,并且重载了该方法,根据传递的参数不同会调用相应的方法。
      //该方法的参数含义:第一个参数应该和配置信息相关,第二个参数是事务隔离级别,第三个参数是是否开启事务

      //底层所执行的代码
      TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //很显然,其底层采用了工厂设计模式。先得到TransactionFactory对象,再通过该对象得到Transaction对象,此时autoCommit=false
      public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
      return new JdbcTransaction(ds, level, autoCommit, this.skipSetAutoCommitOnClose);
      }
      //通过以上代码可知,返回的是一个jdbc事务(t)
      //调用openConnction()方法
      protected void openConnection() throws SQLException {
      this.setDesiredAutoCommit(this.autoCommit);
      }
      //调用setDesiredAutoCommit(Boolean boolean)方法
      protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
      try {
      //在jdbc中connection.getAutoCommit()默认是等于true的
      if (this.connection.getAutoCommit() != desiredAutoCommit) {
      //由于desiredAutoCommit为false,所以执行该语句,开启事务
      this.connection.setAutoCommit(desiredAutoCommit);
      }

      } catch (SQLException var3) {
      }
      }
      * 通过源码分析可得:如果我们采用SqlSessionFactory.openSsion(true);来获得SqlSession,那么是不开启事务的,默认是自动提交语句的。也就是说不需要SqlSession.commit,但是不建议这样做。
    • 当value是managed时,表示MyBatis不管理事务,而是交给其他容器比如Spring来管理事务。目前来说MyBatis不管理事务就意味着没人管理事务,也就是没开启事务,即自动提交DML。

  • 总结:只要MyBatis中autoCommit值为true,表示不开启事务