阅读iBatis源码时,对事务相关的代码,没太关注,导致今天项目技术演练时对同事的疑问,解释不清楚。自己都不清楚的东西,怎么可能向别人解释清楚呢?所以,就干脆继续看iBatis源码,完整跟踪事务的处理流程。重新分析代码,发现iBatis原来使用了代理模式,同时理解了iBatis的线程安全的保证机制及事务控制流程。
顶层类图
线程安全的保证
iBatis的SqlMapClient和SqlMapSession有相同的继承关系,而SqlMapClient的实现类则关联了一个SqlMapSession的实现类。这是典型的代理模式,只是SqlMapClientImpl这个代理对象仅仅是做了功能的转发而已。SqlMapClientImpl类使用了ThreadLocal类型的成员变量来存储关联的SqlMapSessionImpl对象。这就是限制了每个线程都只能操作自己记录的SqlMapSessionImpl数据,从而保证了该属性的线程安全。
SqlMapSessionImpl关联一个SessionScope,记录了一次与数据库的连接所有的信息,SqlMapSessionImpl的所有操作都依赖于该属性。因此它也是线程安全的。SqlMapClientImpl实现CRUD操作都是转发当前线程的SqlMapSessionImpl对象的,而且所有SQL执行操作都依赖当前的SessionScope,代码如下:
public Object insert(String id, Object param) throws SQLException { return getLocalSqlMapSession().insert(id, param); }
protected SqlMapSessionImpl getLocalSqlMapSession() { SqlMapSessionImpl sqlMapSession = (SqlMapSessionImpl) localSqlMapSession.get(); if (sqlMapSession == null || sqlMapSession.isClosed()) { sqlMapSession = new SqlMapSessionImpl(this); localSqlMapSession.set(sqlMapSession); } return sqlMapSession; }
事务基础
iBatis的SqlMapClient提供了事务处理方法如下:
事务相关的类图
事务的状态转换图如下:
SqlMapSessionImpl实现TransactionManager事务相关的四个方法,本质上就是操作它关联的SessionScope中有关事务的属性,即Transaction 和TransactionState。例如:startTransaction方法会根据配置的事务管理器,新建一个事务对象,并设置事务状态为STATE_STARTED。其他跟事务有关的处理大多都是根据操作调用JDBC的Connection的对应的事务处理方法。endTransaction方法会根据事务状态,提交或者回滚SQL操作,最后会关闭JDBC语句和数据库连接。
iBatis源码中使用到的Session的含义是与数据库的一次完整的会话过程,从开启到结束,体现在四个事务操作方法中,所有的SQL执行操作,最终都是通过JDBC的Connection完成的。