mybatis源码解析(一)-开篇
mybatis源码解析(二)-加载过程
mybatis源码解析(三)-SqlSession.selectOne类似方法调用过程
mybatis源码解析(四)-Mapper方法调用过程
mybatis源码解析(五)-mybatis如何实现的事务控制
mybatis源码解析(六)-配合spring-tx实现事务的原理
mybatis源码解析(七)-当mybatis一级缓存遇上spring
转载请标明出处:
http://blog.csdn.net/bingospunky/article/details/79283104
本文出自马彬彬的博客
这篇博客主要展示mybatis是如何控制事务的。
下面两个例子分别展示一下我们使用/不使用Trancation的例子。
Code 1不使用事务,自动提交
SqlSession session = sqlSessionFactory.openSession(true);
session.insert("insert into table1(id, name) values(1, 'a');");
session.insert("insert into table1(id, name) values(2, 'b');");
Code 2使用事务,不自动提交
SqlSession session = sqlSessionFactory.openSession(false);
try {
session.insert("insert into table1(id, name) values(1, 'a');");
session.insert("insert into table1(id, name) values(2, 'b');");
session.commit();
} catch (Exception e) {
session.rollback();
}
在mybatis api中,控制Trancation是在创建org.apache.ibatis.session.SqlSession的时候设置boolean类型的参数来实现的。调用方法没有差别,支持事务的最后会调用commoit或者rollback。
创建org.apache.ibatis.session.SqlSession的过程如下:
Code 3
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
第7行创建了Transaction对象。第8行创建了Executor对象。第9行创建了SqlSession对象。下面第这三个对象做一个简单介绍:
用户直接操作的对象,该对象对用户调用的方法进行一些简单的处理,然后调用Executor的方法执行具体的操作。
可以注意一下,该对象维护了一个private boolean dirty;用来标记在上次commit之后有没有执行新的增、删、改操作。该类的commit会根据这个属性来确定会不会执行jdbc代码的commit方法,也可以强制commit而跳过这个属性的限制。
该对象是具体执行sql的类,它操作的是org.apache.ibatis.mapping.MappedStatement,这个对象在执行真正的sql时,会使用jdbc的java.sql.Connection,但是它不会去生成、维护这个java.sql.Connection,它包含了一个org.apache.ibatis.transaction.Transaction,由Transaction这个对象去维护Transaction。
这是个接口,接口的定义如下:
Code 4
org.apache.ibatis.transaction.Transaction
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
}
它的一个实现类org.apache.ibatis.transaction.jdbc.JdbcTransaction,这个类里维护了DataSource,在需要的时候会创建java.sql.Connection,在创建完java.sql.Connection后,会根据创建org.apache.ibatis.session.SqlSession时传递的参数值,设置java.sql.Connection是否自动提交。该类也提供了对Connection执行commit、rollback的方法,在org.apache.ibatis.session.SqlSession执行commit、rollback方法时,都会传递到这里的方法。
我们使用Jdbc进行事务控制的话,也是调用java.sql.Connection.setAutoCommit设置是否开启事务,调用java.sql.Connection.commit或java.sql.Connection.rollback进行调或回滚。在mybatis代码中,通过org.apache.ibatis.session.SqlSession的创建设置是否支持事务,调用org.apache.ibatis.session.SqlSession.commit、org.apache.ibatis.session.SqlSession.rollback方法会映射到对应Jdbc的方法,这样就足以支持了事务。