MyBatis源码解析(三)——Transaction事务模块

原创作品,可以转载,但是要标注出处地址:http://www.cnblogs.com/V1haoge/p/6634151.html

1、回顾

  之前介绍了Environment环境类,这其实是一个单例类,在MyBatis运行开启后仅仅见面在一个唯一的环境实例,虽然咱得以Configuration配置文件被配备多单环境,但是项目周转面临才见面存在里面的一个,一般品种会在开发条件暨测试环境、生产环境三生条件,其是否足以安装到布置文件被,在支付时用支付条件,测试时以测试环境,正式营业时可以应用生产条件。

  之前还干Environment类中来三单字段,除了id之外,TransactionFactory和DataSource都是比较复杂的模块,这同破我们介绍Transaction模块(即工作模块)。

2、事务模块

  事务模块位于org.apache.ibatis.transaction保证,这个包内的好像都是工作相关的切近:

  org.apache.ibatis.transaction
  -----org.apache.ibatis.transaction.jdbc
  ----------JdbcTransaction.java
  ----------JdbcTransactionFactory.java
  -----org.apache.ibatis.transaction.managed
  ----------ManagedTransaction.java
  ----------ManagedTransactionFactory.java
  -----Transaction.java
  -----TransactionException.java
  -----TransactionFactory.java

  从点的类似组织被也克看出来,MyBatis的工作模块采用的是厂模式。

2.1 事务接口

  位于org.apache.ibatis.transaction包的Transaction和TransactionFactory都是对接口类。

  Transaction是业务接口,其中定义了季个方式:

      commit()-事务提交

      rollBack()-事务回滚

      close()-关闭数据库连接

      getConnection()-获取数据库连接

  如下代码所示:

 1 package org.apache.ibatis.transaction;
 2 import java.sql.Connection;
 3 import java.sql.SQLException;
 4 /**
 5  * 事务,包装了一个Connection, 包含commit,rollback,close方法
 6  * 在 MyBatis 中有两种事务管理器类型(也就是 type=”[JDBC|MANAGED]”):  
 7  */
 8 public interface Transaction {
 9   Connection getConnection() throws SQLException;
10   void commit() throws SQLException;
11   void rollback() throws SQLException;
12   void close() throws SQLException;
13 }

  TransactionFactory是事情工厂接口,其中定义了三独措施:

      setProperties(Properties props)-设置属性

      newTransaction(Connection conn)-创建工作实例

      newTransaction(DataSource
dataSource,TransactionIsolationLevel level,boolean
autoCommit)-创建工作实例

  如下代码所示:

 1 package org.apache.ibatis.transaction;
 2 import java.sql.Connection;
 3 import java.util.Properties;
 4 import javax.sql.DataSource;
 5 import org.apache.ibatis.session.TransactionIsolationLevel;
 6 /**
 7  * 事务工厂
 8  */
 9 public interface TransactionFactory {
10   //设置属性
11   void setProperties(Properties props);
12   //根据Connection创建Transaction
13   Transaction newTransaction(Connection conn);
14   //根据数据源和事务隔离级别创建Transaction
15   Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
16 }

  Transacrion接口定义的目的就是是以对现实的事情型进行抽象,便于扩展;TransactionFactory与那平,是对准事情工厂的肤浅,同样有益具体项目的作业工厂的壮大实现。

2.2 MyBatis事务类型

  说到此,就只能干MyBatis里搁的有限栽工作型以及相应之工作工厂了,还记在达成一致软遭遇吃出底environment配置信息,有这样一词:

 <transactionManager type="JDBC"/>

  这里的<transactionManager>标签便用来定义项目所祭的工作型,具体的类别由type属性来指定,此处指定使用“JDBC”类型事务,当然MyBatis还提供了另外一栽“MANAGED”型业务。

    —JDBC

    —MANAGED

  这里的“JDBC”和“MANAGED”是当Configuration配置类的色别名注册器中注册之号,其对应的接近分别是:JdbcTransactionFactory.class和ManagedTransactionFactory.class。具体的配备如下所陈述:

1  typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
2  typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

  上面的代码是在Configuration类的凭参构造器中定义之,这里用来就用于展示,具体说明之后会介绍。

  这里取一词:类型别名注册器额原理就是是以别名与实际的类类型以键值对之艺术保留至一个HashMap中,这样一旦知道别名(键),就可从Map中落相应的价(Class类型),很简短!

  现在若了解MyBatis能够根据你在配备文件被安装的事务型,直接找到相应的事情工厂类即推行了。

  下面对上面提到的星星点点种植业务型进行解读。

      —JDBC事务型:JdbcTransaction

      —MANAFED事务型:ManagedTransaction

  二者的不同之处在于:前者是直接运用JDK提供的JDBC来管理工作之各个环节:提交、回滚、关闭等操作,而后人则什么还未开,那么后者来啊含义吗,当然非常重要。

  当我们单独采取MyBatis来构建项目时,我们如果当Configuration配置文件中开展环境(environment)配置,在其间倘装工作型为JDBC,意思是说MyBatis被单独行使时便待以JDBC类型的事体型,因为以这个模型中定义了作业的各个方面,使用她好完成作业的各类操作。而MANAGED类型的业务型其实是一个托管型,也就是说它自身并无落实任何事情功能,而是托管出去是因为另外框架来贯彻,你可能还未掌握,这个事情的有血有肉落实即交由而Spring之类的框架来兑现,而且于以SSM整合框架后就不复用单独安排环境信息(包括工作配置和数据源配置),因为于当整合jar包(mybatis-spring.jar)中享有覆盖mybatis里面的即时有的逻辑的代码,实际情况是不怕你显式设置了相关配置信息,系统啊会视而不见……

  托管的含义不言而喻,正是为整合而设。

  我们学MyBatis的目的正是出于该灵活性与及Spring等框架的无缝结合的力量,所以有关JDBC事务模块的情明显不再是MyBatis功能中之关键,也许只有当单独行使MyBatis的微量系遭到才会以及。

2.3 JDBC事务型

  虽然JDBC事务型大少用到,但是作为MyBatis不可分割的如出一辙有,我们要要展开得的打听,JDBC事务的兑现是对准JDK中提供的JDBC事务模块的再度装进,以适用于MyBatis环境。

  MyBatis中之JDBC事务模块包括个别个部分,分别吗JDBC事务工厂及JDBC事务,整个工作模块采用的凡抽象工厂模式,那么相应于每一样项具体的事务处理模块必然有和谐之政工工厂,事务模块实例通过业务工厂来创造(事务工厂将现实的作业实例的始建封装起来)。

  首先我们来看JDBC事务工厂:JdbcTransactionFactory

  JdbcTransactionFactory继承自TransactionFactory接口,实现了其中的具备办法。分别吗一个装属性的主意以及个别个新建事务实例的章程(参数不同),内容十分简短,作用吧不行简短。

  其中setProperties()方法用于安装属性,这个办法在XMLConfigBuilder中剖析事务标签时调用,用于解析事务标签的手下人属性标签<property>(一般景象下我们连无见面进行安装,但是要是我们开展了设置,那即便会覆盖MyBatis中的默认设置)之后以该安装及开创的事体实例中。然而对JDBC事务型,在作业工厂的装属性方法吃从不其他履行代码,也就是证明JDBC事务模块并无支持设置属性的功能,即使你于配置文件被设置的片段信,也未会见来任何作用。

  那么是办法来什么用啊?前面提到,这个装置用于覆盖默认设置,只是JDBC事务模块并无支持而已,但连无代表别的事情型不支持,同时这艺术为只是用以功能扩展。

  另外两只点子显著,就是用来创造JDBC事务实例的养法,只是参数不同,方法的重载而已。其中一个生产方法才需要传递一个实例Connection,这象征一个数据库连接。而其他一个智要传递三个参数(DataSource、TransactionIsolationLevel、boolean),其实就对准应于MyBatis中SqlSession的少种生产方式,其参数与此一一对应,这部分内容后介绍,此处不再赘述。

  然后我们来探视JDBC事务类:JdbcTransaction

  其中有四单参数:

1   protected Connection connection;
2   protected DataSource dataSource;
3   protected TransactionIsolationLevel level;
4   protected boolean autoCommmit;

  这四独参数MyBatis分别对应事务工厂面临之简单个生产方法中的总计四单参数,对应之于事务类中定义了点儿独构造器,构造实例的同时拓展赋值:

1   public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
2     dataSource = ds;
3     level = desiredLevel;
4     autoCommmit = desiredAutoCommit;
5   }
6   public JdbcTransaction(Connection connection) {
7     this.connection = connection;
8   }

  其次在此类中落实了Transaction接口,实现了内部的季个方法,三单功能性方法,和一个获取数据库连接的措施。三独职能方法分别是交、回滚和关闭。

 1   @Override
 2   public void commit() throws SQLException {
 3     if (connection != null && !connection.getAutoCommit()) {
 4       if (log.isDebugEnabled()) {
 5         log.debug("Committing JDBC Connection [" + connection + "]");
 6       }
 7       connection.commit();
 8     }
 9   }
10 
11   @Override
12   public void rollback() throws SQLException {
13     if (connection != null && !connection.getAutoCommit()) {
14       if (log.isDebugEnabled()) {
15         log.debug("Rolling back JDBC Connection [" + connection + "]");
16       }
17       connection.rollback();
18     }
19   }
20 
21   @Override
22   public void close() throws SQLException {
23     if (connection != null) {
24       resetAutoCommit();
25       if (log.isDebugEnabled()) {
26         log.debug("Closing JDBC Connection [" + connection + "]");
27       }
28       connection.close();
29     }
30   }

  通过观察这三独道,可以发现,其中都采取了connection来开展具体操作,因此这些艺术应用的前提就是是先拿走connection数据库连接,Connection的获得使用getConnection()方法

1   @Override
2   public Connection getConnection() throws SQLException {
3     if (connection == null) {
4       openConnection();
5     }
6     return connection;
7   }

  在方的方被调用了openConnection()方法:

 1  protected void openConnection() throws SQLException {
 2     if (log.isDebugEnabled()) {
 3       log.debug("Opening JDBC Connection");
 4     }
 5     connection = dataSource.getConnection();
 6     if (level != null) {
 7       connection.setTransactionIsolation(level.getLevel());
 8     }
 9     setDesiredAutoCommit(autoCommmit);
10   }

  可见connection是起数额源dataSource中取之,最后会调用setDesiredAutoCommit()方法:

 1   protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
 2     try {
 3       if (connection.getAutoCommit() != desiredAutoCommit) {
 4         if (log.isDebugEnabled()) {
 5           log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
 6         }
 7         connection.setAutoCommit(desiredAutoCommit);
 8       }
 9     } catch (SQLException e) {
10       // Only a very poorly implemented driver would fail here,
11       // and there's not much we can do about that.
12       throw new TransactionException("Error configuring AutoCommit.  "
13           + "Your driver may not support getAutoCommit() or setAutoCommit(). "
14           + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);
15     }
16   }

  这个点子的目的就是啊connection中的全自动提交赋值(真要借用)。

  这么看来,我们创建工作实例所提供的老三单参数就是吗connection服务的,其中DataSource是为此来取Connection实例的,而TransactionIsolationLevel(事务级别)和boolean(自动提交)是故来填充connection的,通过三独参数我们获得了一个宏观的Connection实例,然后我们不怕得使用这实例来展开作业操作:提交、回滚、关闭。

2.4 关于机关提交

  于头里的代码中我们能够来看在关操作前调用了一个道:resetAutoCommit():

 1   protected void resetAutoCommit() {
 2     try {
 3       if (!connection.getAutoCommit()) {
 4         // MyBatis does not call commit/rollback on a connection if just selects were performed.
 5         // Some databases start transactions with select statements
 6         // and they mandate a commit/rollback before closing the connection.
 7         // A workaround is setting the autocommit to true before closing the connection.
 8         // Sybase throws an exception here.
 9         if (log.isDebugEnabled()) {
10           log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
11         }
12         connection.setAutoCommit(true);
13       }
14     } catch (SQLException e) {
15       log.debug("Error resetting autocommit to true "
16           + "before closing the connection.  Cause: " + e);
17     }
18   }

  这里相对自动提交做只说明,如果安自动提交也确实,那么数据库将会拿各一个SQL语句当做一个事务来执行,为了以多长长的SQL当做一个事情进行付出,必须将自行提交设置为false,然后进行手动提交。一般以咱们的档次被,都要以机关提交设置也false,即将自动提交关闭,使用手动提交

  这个艺术被经过对connection实例中的全自动提交设置(真要借用)进行判定,如果为false,表明无履机关提交,则复位,重新将其安装为true。(自动提交的默认值为true)这个操作实践于connection关闭之前。可以看做是连续关闭前的复位操作。

2.5 问题

  以JdbcTransaction中提供的星星单构造器中因为Connection为参数的构造器额作用是啊呢?

  我们得活动组装一个完整的Connection,以那个也参数来养一个政工实例。这所以在什么状况中也?

网站地图xml地图