iBatis整理——Spring环境下批处理实现

最近做一个小项目,用到Spring+iBatis。突然遇到一个很久远,却很实在的问题:在Spring下怎么使用iBatis的批处理实现?

大概是太久没有写Dao了,这部分真的忘得太干净了。 :)

从4个层面分析这部分实现:
[list=1]
[*]iBatis的基本实现
[*]基于事务的iBatis的基本实现
[*]基于事务的Spring+iBatis实现
[*]基于回调方式的Spring+iBatis实现
[/list]

[b][size=large]1.iBatis的基本实现[/size][/b]
iBatis通过SqlMapClient提供了一组方法用于批处理实现:
[list=1]
[*]startBatch() 开始批处理
[*]executeBatch() 执行批处理
[/list]
代码如下:

public void create(List<Reply> replyList) {

try {
// 开始批处理
sqlMapClient.startBatch();

for (Reply reply: replyList) {
// 插入操作
sqlMapClient.insert("Reply.create", reply);
}
// 执行批处理
sqlMapClient.executeBatch();

} catch (Exception e) {
e.printStackTrace();
}
}

这是基于iBatis的最基本实现,如果你一步一步debug,你会发现:其实,数据库已经执行了插入操作!
[color=red][b]因此,除了这两个核心方法外,你还需要开启事务支持。否则,上述代码只不过是个空架子![/b][/color]

[b][size=large]2.基于事务的iBatis的基本实现[/size][/b]
事务处理:
[list=1]
[*]startTransaction() 开始事务
[*]commitTransaction() 提交事务
[*]endTransaction() 结束事务
[/list]

我们以insert操作为例,把它们结合到一起:

public void create(List<Reply> replyList) {

try {
// 开始事务
sqlMapClient.startTransaction();
// 开始批处理
sqlMapClient.startBatch();

for (Reply reply: replyList) {
// 插入操作
sqlMapClient.insert("Reply.create", reply);
}
// 执行批处理
sqlMapClient.executeBatch();

// 提交事务
sqlMapClient.commitTransaction();

} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 结束事务
sqlMapClient.endTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

[b]replyList[/b]是一个List,要把这个List插入到数据库,就需要经过这三个步骤:
[list=1]
[*]开始批处理 startBatch()
[*]插入 insert()
[*]执行批处理 executeBatch()
[/list]
[color=red][b]如果要在Spring+iBatis中进行批处理实现,需要注意使用同一个sqlMapClient!同时,将提交事务的工作交给Spring统一处理![/b][/color]

[b][size=large]3.基于事务的Spring+iBatis实现[/size][/b]

public void create(List<Reply> replyList) {
if (!CollectionUtils.isEmpty(replyList)) {
// 注意使用同一个SqlMapClient会话
SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();

try {
// 开始事务
sqlMapClient.startTransaction();
// 开始批处理
sqlMapClient.startBatch();
for (Reply reply : replyList) {
// 插入操作
sqlMapClient.insert("Reply.create", reply);
}

// 执行批处理
sqlMapClient.executeBatch();
// 提交事务 交给Spring统一控制
// sqlMapClient.commitTransaction();

} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 结束事务
sqlMapClient.endTransaction();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

注意使用同一个sqlMapClient:
[b]SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();[/b]
[b]如果直接sqlMapClientTemplate执行insert()方法,将会造成异常![/b]

[color=red][b]想想,还有什么问题?其实问题很明显,虽然解决了批处理实现的问题,却造成了事务代码入侵的新问题。 :( 这么做,有点恶心!
除此之外,异常的处理也很恶心,不能够简单的包装为 DataAccessException 就无法被Spring当作统一的数据库操作异常做处理。
[/b][/color]

[b][size=large]4.基于回调方式的Spring+iBatis实现[/size][/b]
如果观察过Spring的源代码,你一定知道,Spring为了保持事务统一控制,在实现ORM框架时通常都采用了回调模式,从而避免了事务代码入侵的可能! :D
修改后的代码如下:

@SuppressWarnings("unchecked")
public void create(final List<Reply> replyList) {
// 执行回调
sqlMapClientTemplate.execute(new SqlMapClientCallback() {
// 实现回调接口
public Object doInSqlMapClient(SqlMapExecutor executor)
throws SQLException {
// 开始批处理
executor.startBatch();
for (Reply reply : replyList) {
// 插入操作
executor.insert("Reply.create", reply);

}
// 执行批处理
executor.executeBatch();

return null;

}
});

}

[b]注意,待遍历的参数replyList需要加入final标识!即,待遍历对象不能修改![/b]
[quote]public void create(final List<Reply> replyList) [/quote]
[b]这样做,就将事务处理的控制权完全交给了Spring![/b] :D
简述:
[list=1]
[*]SqlMapClientCallback 回调接口
[*]doInSqlMapClient(SqlMapExecutor executor) 回调实现方法
[*]DataAccessException 最终可能抛出的异常
[/list]
通过上述修改,最终能够解决第三种实现方式中的种种不足! :D

Spring对iBatis提供的支持还是不够完善,即便是现在最新的Spring3.0.4。最开始,本打算用Spring3.0+iBatis3.0,结果Spring报错,说找不到“com.ibatis.xxxxx”完全是iBatis2.x的包路径!汗颜~ :( 还是Hibernate比较得宠! :D

做个小记录,呵呵! :D
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值