在看iBatis的文档时,其描述的典型批处理语句如下:
try {
sqlMap.startTransaction();
sqlMap.startBatch();
// … execute statements in between
int rowsUpdated = sqlMap.executeBatch(); //optional
sqlMap.commitTransaction();
} finally {
sqlMap.endTransaction();
}
这段语句,如果由iBatis自己来管理事务,相信大家没有使用任何的疑虑。但是,如果已经由Spring来托管事务,这段语句是不是有问题呢????
其实,我开始的时候这种疑问是非常强烈的,所以,有时我会这样写:
sqlMap.startBatch();
// … execute statements in between
int rowsUpdated = sqlMap.executeBatch(); //optional
但是在运行时发现,批语句根本不起作用,后来查看源代码才知道:iBatis不管事务由谁来管理,批处理的方式是完全一致的!
那么sqlMap.startTransaction();sqlMap.commitTransaction();sqlMap.endTransaction();这三个语句难道不会对全局事务有任何影响吗??答案是:没有任何影响!
相信大家将Spring与IBatis集成时,都会使用如下的方式:
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation">
<value>classpath:sqlMapConfig-${database.type}.xml</value>
</property>
<property name="dataSource" ref="dataSource" />
</bean>
查看SqlMapClientFactoryBean的源码,发现
……
private Class transactionConfigClass = ExternalTransactionConfig.class;
……
public void afterPropertiesSet() throws Exception {
……
TransactionConfig transactionConfig = (TransactionConfig) this.transactionConfigClass.newInstance();
……
}
……
也就是说,TransactionConfig 的类型是ExternalTransactionConfig。在运行时,ExternalTransactionConfig会构造出ExternalTransaction!
查看ExternalTransaction的源码,会发现rollback()和commit()方法不做任何事情!至此,我们就会明白:当Spring与iBatis集成时,iBatis的事务处理语句对全局事务不会有任何的影响!
结论:无论在何种情况之下,请放心大胆的使用iBatis文档中的调用方式,结果总是正确的!
实际上,你还可以通过继承SqlMapClientDaoSupport,以如下的方式进行处理:
getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
executor.startBatch();
executor.update("insertSomething", "myParamValue");
executor.update("insertSomethingElse", "myOtherParamValue");
executor.executeBatch();
return null;
}
});