ibatis3 加spring 怎么用批处理啊?求解答

ibatis3 加spring 怎么用批处理啊?注:是itatis3 不是2哦

4个回答

家我QQ,回家给你看看我之前的项目

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

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

从4个层面分析这部分实现:

•iBatis的基本实现
•基于事务的iBatis的基本实现
•基于事务的Spring+iBatis实现
•基于回调方式的Spring+iBatis实现

1.iBatis的基本实现
iBatis通过SqlMapClient提供了一组方法用于批处理实现:

•startBatch() 开始批处理
•executeBatch() 执行批处理

代码如下:

Java代码 •public void create(List replyList) {



• try {

• // 开始批处理

• sqlMapClient.startBatch();



• for (Reply reply: replyList) {

• // 插入操作

• sqlMapClient.insert("Reply.create", reply);

• }

• // 执行批处理

• sqlMapClient.executeBatch();



• } catch (Exception e) {

• e.printStackTrace();

• }

•}

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

2.基于事务的iBatis的基本实现
事务处理:

•startTransaction() 开始事务
•commitTransaction() 提交事务
•endTransaction() 结束事务

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

Java代码 •public void create(List 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();

• }

• }

•}

replyList是一个List,要把这个List插入到数据库,就需要经过这三个步骤:

•开始批处理 startBatch()
•插入 insert()
•执行批处理 executeBatch()

如果要在Spring+iBatis中进行批处理实现,需要注意使用同一个sqlMapClient!同时,将提交事务的工作交给Spring统一处理!

3.基于事务的Spring+iBatis实现

Java代码 •public void create(List 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:
SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();
如果直接sqlMapClientTemplate执行insert()方法,将会造成异常!

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

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

Java代码 •@SuppressWarnings("unchecked")

•public void create(final List 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;



• }

• });



•}

注意,待遍历的参数replyList需要加入final标识!即,待遍历对象不能修改!

引用
public void create(final List replyList)

这样做,就将事务处理的控制权完全交给了Spring!
简述:

•SqlMapClientCallback 回调接口
•doInSqlMapClient(SqlMapExecutor executor) 回调实现方法
•DataAccessException 最终可能抛出的异常

通过上述修改,最终能够解决第三种实现方式中的种种不足!

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

干嘛用ibatis半导体,直接hibernate多好

[code="java"]
其实网上很多例子iBatis批处理的总结都有问题。下面把偶的测试报告和准确的写法总结一下:

下面这种写发是错误的也是网上说批处理方案之一:

public Dto batchSaveSfxmDomains(Dto pDto) throws SQLException {

Dto outDto = new BaseDto();

SqlMapClient sqlMapClient = g4Dao.getSqlMapClientTpl().getSqlMapClient();

try {

sqlMapClient.startTransaction();

sqlMapClient.startBatch();

for (int i = 0; i < pDto.getAsInteger("count").intValue(); i++) {

String xmid = IDHelper.getXmID();

pDto.put("xmid", xmid);

g4Dao.insert("insertEz_sfxmDomain", pDto);

}

int rows = g4Dao.getSqlMapClientTpl().getSqlMapClient().executeBatch();

} catch (SQLException e) {

e.printStackTrace();

throw e;

}finally{

sqlMapClient.commitTransaction();

sqlMapClient.endTransaction();

}

return outDto;

}

这种写法,如果此方法的autocommit属性为true则他的效率会非常低下很耗时。如果将其纳入事务管理容器也就是将autocommit属性设为false,则其效率将有明显大幅提高。但这种batch写法和不使用batch写法将其纳入事务容器效率基本持平,而且通过监控可以明显看到这种写法是将sql语句一条一条顺序发送给数据库的,并没有压缩后批量发送的优势。他的优势仅仅是由于事务的原子提交而带来的效率提升。

正确的写法在此:

public Dto batchSaveSfxmDomains1(final Dto pDto) throws SQLException {

Dto outDto = new BaseDto();

g4Dao.getSqlMapClientTpl().execute(new SqlMapClientCallback() {

public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {

executor.startBatch();

for (int i = 0; i < pDto.getAsInteger("count").intValue(); i++) {

Dto pDto = new BaseDto();

String xmid = IDHelper.getXmID();

pDto.put("xmid", xmid);

executor.insert("insertEz_sfxmDomain", pDto);

}

executor.executeBatch();

return null;

}

});

return outDto;

}

这种写法不但活得了原子提交的性能提升也活得了batch压缩批量发送sql语句的Batch优势,经测试这种方式的性能是最高的。

批注:

在执行批处理时,方法update和executeBatch的返回值(影响的记录数)不靠谱。不同的JDBC驱动实现不一样有的返回有的不返回。

[/code]

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!