從4個層面分析這部分實現:
1.iBatis的基本實現
iBatis通過SqlMapClient提供了一組方法用于批處理實現:
代碼如下:
這是基于iBatis的最基本實現,如果你一步一步debug,你會發現:其實,數據庫已經執行了插入操作!
因此,除了這兩個核心方法外,你還需要開啟事務支持。否則,上述代碼只不過是個空架子!
2.基于事務的iBatis的基本實現
事務處理:
我們以insert操作為例,把它們結合到一起:
replyList是一個List,要把這個List插入到數據庫,就需要經過這三個步驟:
如果要在Spring+iBatis中進行批處理實現,需要注意使用同一個sqlMapClient!同時,將提交事務的工作交給Spring統一處理!
3.基于事務的Spring+iBatis實現
注意使用同一個sqlMapClient:
SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();
如果直接sqlMapClientTemplate執行insert()方法,將會造成異常!
想想,還有什么問題?其實問題很明顯,雖然解決了批處理實現的問題,卻造成了事務代碼入侵的新問題。
這么做,有點惡心!
除此之外,異常的處理也很惡心,不能夠簡單的包裝為 DataAccessException 就無法被Spring當作統一的數據庫操作異常做處理。
4.基于回調方式的Spring+iBatis實現
如果觀察過Spring的源代碼,你一定知道,Spring為了保持事務統一控制,在實現ORM框架時通常都采用了回調模式,從而避免了事務代碼入侵的可能!
修改后的代碼如下:
注意,待遍歷的參數replyList需要加入final標識!即,待遍歷對象不能修改!
這樣做,就將事務處理的控制權完全交給了Spring!
簡述:
- iBatis的基本實現
- 基于事務的iBatis的基本實現
- 基于事務的Spring+iBatis實現
- 基于回調方式的Spring+iBatis實現
1.iBatis的基本實現
iBatis通過SqlMapClient提供了一組方法用于批處理實現:
- startBatch() 開始批處理
- executeBatch() 執行批處理
代碼如下:
- 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,你會發現:其實,數據庫已經執行了插入操作!
因此,除了這兩個核心方法外,你還需要開啟事務支持。否則,上述代碼只不過是個空架子!
2.基于事務的iBatis的基本實現
事務處理:
- startTransaction() 開始事務
- commitTransaction() 提交事務
- endTransaction() 結束事務
我們以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();
- }
- }
- }
replyList是一個List,要把這個List插入到數據庫,就需要經過這三個步驟:
- 開始批處理 startBatch()
- 插入 insert()
- 執行批處理 executeBatch()
如果要在Spring+iBatis中進行批處理實現,需要注意使用同一個sqlMapClient!同時,將提交事務的工作交給Spring統一處理!
3.基于事務的Spring+iBatis實現
- 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:
SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();
如果直接sqlMapClientTemplate執行insert()方法,將會造成異常!
想想,還有什么問題?其實問題很明顯,雖然解決了批處理實現的問題,卻造成了事務代碼入侵的新問題。

除此之外,異常的處理也很惡心,不能夠簡單的包裝為 DataAccessException 就無法被Spring當作統一的數據庫操作異常做處理。
4.基于回調方式的Spring+iBatis實現
如果觀察過Spring的源代碼,你一定知道,Spring為了保持事務統一控制,在實現ORM框架時通常都采用了回調模式,從而避免了事務代碼入侵的可能!

修改后的代碼如下:
- @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;
- }
- });
- }
注意,待遍歷的參數replyList需要加入final標識!即,待遍歷對象不能修改!
引用
public void create(final List<Reply> replyList)
這樣做,就將事務處理的控制權完全交給了Spring!

簡述:
- SqlMapClientCallback 回調接口
- doInSqlMapClient(SqlMapExecutor executor) 回調實現方法
- DataAccessException 最終可能拋出的異常