Mybatis是一个支持自定义SQL语句,存储过程,高级映射的数据持久化框架。
它封装了JDBC,在框架中隐藏了几乎所有的JDBC的API,这里说下从源码的角度Mybatis 3.x (笔者用的是3.2.8)是如何封装JDBC来实现事务处理的。
回忆下mybatis是怎么使用事务管理的,session.commit(),session.rollback(), JDBC呢,是connection.commit(),connection.rollback()。所以这篇文章的内容就变成了如何从session.commit()到connection.commit()。
首先从session来看看,我们获得一个session对象其实是DefaultSqlSession对象,这个类中的commit() 方法如下。
public void commit() {commit(false);}public void commit(boolean force) {try {executor.commit(isCommitOrRollbackRequired(force));dirty = false;} catch (Exception e) {throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e);} finally {ErrorContext.instance().reset();}}private boolean isCommitOrRollbackRequired(boolean force) {return (!autoCommit && dirty) || force;}
然后到CachingExecutor 中的方法
public void commit(boolean required) throws SQLException {delegate.commit(required);tcm.commit();}//也许对这执行commit的对象不熟悉,看下面
private Executor delegate;
private TransactionalCacheManager tcm = new TransactionalCacheManager();
所以真正我们关心的事务是另外一个Executor,BaseExecutor中commit()方法
public void commit(boolean required) throws SQLException {if (closed) throw new ExecutorException("Cannot commit, transaction is already closed");clearLocalCache();flushStatements();if (required) {transaction.commit();}}
前面两个方法是跟缓存相关,只有最后一个才是我们关心的,JDBCTransaction类中的commit()
public void commit() throws SQLException {if (connection != null && !connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Committing JDBC Connection [" + connection + "]");}connection.commit();}}
现在我们明白了,JDBCTransaction中包装了一个connection的对象。这也是我们在使用mybatis配置文件时设置的事务管理类。