`
yjhexy
  • 浏览: 327250 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

IBATIS batch用法探究

阅读更多

  有的时候需要一次性执行大批量的SQL,而不是执行一条SQL向数据库提交一次,那么会

 

用到 IBATIS 的batch提交。

 

IBATIS的 batch提交也是基于 JDBC的batch功能。

 

  那么我现来写段代码示范一下:

 

第一步,建立我的测试类。

其中 BabyDO,sexEnum 等类是自己写的,并不重要,只要让程序跑起来,读者可以自己写下。不多讲了,主要讲重点的几个语句。

package com.yajun;

// import  很多JDK给的类

import com.yajun.dataobject.BabyDO;
import com.yajun.enumdemo.SexEnum;
import com.yajun.impl.BabyDAOImpl;

/**
 * 专门测试batch操作的
 * 
 * @author yajun
 * 
 */
public class BatchInsertTest {
	private BabyDAOImpl babyDAO = new BabyDAOImpl();

	public static void main(String[] args) throws SQLException {
		BatchInsertTest test = new BatchInsertTest();
		test.insertBaby();
	}

	// 批量插入婴儿并且插入数据库
	private void insertBaby() throws SQLException {
		List<BabyDO> babys = new ArrayList<BabyDO>();
		long start = System.currentTimeMillis();
		for (int i = 0; i < 10000; i++) {
			BabyDO baby = new BabyDO();
			baby.setName("乌鸦军");
			baby.setSex(SexEnum.Male);
			baby.setBirthday(new Date());
			baby.setHobby("踢寂寞足球");
			baby.setAge(i);
			babys.add(baby);
		}
		int count = babyDAO.insertBatch(babys);
		long end = System.currentTimeMillis();

		System.out.println("============ 成功插入BABY " + count + "条 =============");
		System.out.println("消费时间 " + (end - start));
	}
}

 

第二步,建立BabyDAO的实现类BabyDAOImpl

 

package com.yajun.impl;

// import  很多JDK给的类

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import com.yajun.dao.BabyDAO;
import com.yajun.dataobject.BabyDO;
import com.yajun.dataobject.BabyTestDO;

public class BabyDAOImpl implements BabyDAO {
	private SqlMapClient client;

	public BabyDAOImpl() {
		try {
			Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
			client = SqlMapClientBuilder.buildSqlMapClient(reader);
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

  ……(省略其他方法)
	/**
	 * 批量添加小孩
	 * 
	 * @param babys
	 * @return
	 * @throws SQLException
	 */
	public Integer insertBatch(List<BabyDO> babys) throws SQLException {
		int count = 0;
		try {
                      // 自己控制事物的开始
			client.startTransaction();
			client.startBatch();
			for (BabyDO babyDO : babys) {
				try {
					client.insert("insert-baby", babyDO);
				} catch (Exception e) {
					System.out.println("插入婴儿失败");
				}

			}
			count = client.executeBatch();
		} finally {
                       // 自己控制事物的结束
			client.endTransaction();
		}
		return count;

	}

	……(省略其他方法)
 

运行起来的结果:

============ 成功插入BABY 10000条 =============
消费时间 2610

 

可以看到插入10000条数据只需要2秒钟。

 

那么这里的关键点是我的注释:需要手工控制事物执行,否则事物会在第一条SQL insert 的时候自动将事物关闭掉。

具体原因的代码请看 IBATIS 源码(主要请注意我加注释的那几句话):

 

public Object insert(SessionScope sessionScope, String id, Object param) throws SQLException {
    Object generatedKey = null;

    MappedStatement ms = getMappedStatement(id);
    Transaction trans = getTransaction(sessionScope);
// 如果trans为空的华autoStart=true;如果不手工控制事物,那么这里就是为空
    boolean autoStart = trans == null;

    try {
// 如果autoStart=true,开启事物
      trans = autoStartTransaction(sessionScope, autoStart, trans);

      SelectKeyStatement selectKeyStatement = null;
      if (ms instanceof InsertStatement) {
        selectKeyStatement = ((InsertStatement) ms).getSelectKeyStatement();
      }

      // Here we get the old value for the key property. We'll want it later if for some reason the
      // insert fails.
      Object oldKeyValue = null;
      String keyProperty = null;
      boolean resetKeyValueOnFailure = false;
      if (selectKeyStatement != null && !selectKeyStatement.isRunAfterSQL()) {
        keyProperty = selectKeyStatement.getKeyProperty();
        oldKeyValue = PROBE.getObject(param, keyProperty);
        generatedKey = executeSelectKey(sessionScope, trans, ms, param);
        resetKeyValueOnFailure = true;
      }

      StatementScope statementScope = beginStatementScope(sessionScope, ms);
      try {
        ms.executeUpdate(statementScope, trans, param);
      }catch (SQLException e){
        // uh-oh, the insert failed, so if we set the reset flag earlier, we'll put the old value
        // back...
        if(resetKeyValueOnFailure) PROBE.setObject(param, keyProperty, oldKeyValue);
        // ...and still throw the exception.
        throw e;
      } finally {
        endStatementScope(statementScope);
      }

      if (selectKeyStatement != null && selectKeyStatement.isRunAfterSQL()) {
        generatedKey = executeSelectKey(sessionScope, trans, ms, param);
      }

// 如果autoStart为true自动提交事务(提交事务以后,后面的SQL就没有在一个BATCH里面了)
      autoCommitTransaction(sessionScope, autoStart);
    } finally {
      autoEndTransaction(sessionScope, autoStart);
    }

    return generatedKey;
  }
 

 

 

 

 

 

分享到:
评论
3 楼 lijunwyf41 2014-06-25  
不错

SqlMapClientTemplate sqlMapClientTemplate = getSqlMapClientTemplate();   
SqlMapClient client = sqlMapClientTemplate.getSqlMapClient();

不一定要实例化一个SqlMapClient ,可以从SqlMapClientTemplate 里面获取
2 楼 yjhexy 2009-09-19  
谢谢给我补上一课,我确实缺少这方面的经验。有很多不懂,还要多向您请教。
1 楼 lixjluck 2009-09-16  
一次执行1000条,会导致事务时间太长,在高并发应用下,导致。。。
50条似乎是一个不错的选择。

相关推荐

Global site tag (gtag.js) - Google Analytics