(线程学习)ibatis中的批量更新过慢

进入batchUpdate源码

    protected ThreadLocal localSqlMapSession = new ThreadLocal();   

    protected SqlMapSessionImpl getLocalSqlMapSession() {
        SqlMapSessionImpl sqlMapSession =                 
           (SqlMapSessionImpl)this.localSqlMapSession.get();
        if (sqlMapSession == null || sqlMapSession.isClosed()) {
            sqlMapSession = new SqlMapSessionImpl(this);
            this.localSqlMapSession.set(sqlMapSession);
        }

        return sqlMapSession;
    }  


  public int batchUpdate(String sqlId, List list) {
        try {
            if (list == null) {
                throw new NullPointerException();
            } else {
                this.getLocalSqlMapSession().startBatch();

                for(int i = 0; i < list.size(); ++i) {
                    this.getLocalSqlMapSession().update(sqlId, list.get(i));
                }

                return this.getLocalSqlMapSession().executeBatch();
            }
        } catch (SQLException var4) {
            var4.printStackTrace();
            throw new RuntimeException(var4.getMessage(), var4);
        }
    }

我们关注

  •    ThreadLocal
  • (1)this.getLocalSqlMapSession().startBatch();  -- 这里设置为true
    • 此处的作用是在后续源码中,他会判断 
      if (statementScope.getSession().isInBatch()) {        
    • 如果为true ,就会把sql 放在一起List集合,再批量执行,否则直接执行!
  • (2)this.getLocalSqlMapSession().update(sqlId, list.get(i));   此处就会去做判断
  • (3)this.getLocalSqlMapSession().executeBatch();   开始批量更新

若想要优化批量更新操作,我们需要控制每次批量操作的数量,例如我遇到的生产环境需要导入1.5w条数据,直接for循环后,全部sql放在List集合再去执行,就会很慢,此时我们需要重写batchUpdate方法,控制每次批量执行的sql语句的量(这里我控制每次批量执行3000条sql语句)

 public int batchUpdate(List<ReceivableDataDetailEntity> list) {
        this.logger.info("=============进入测试的batchUpdate方法===========");
        try {
            if (list == null) {
                throw new NullPointerException();
            } else {
                this.sqlMapClient.startBatch();
                int batch = 0;
                for(int i = 0; i < list.size(); ++i) {
                    logger.info("=============第" +batch+ "次===========");
                    batch++;
                    this.sqlMapClient.update("receivableDataDetail.update", list.get(i));
                    if (batch%3000 == 0){
                        this.sqlMapClient.executeBatch();
                        this.sqlMapClient.startBatch();
                    }
                }
                this.logger.info("=============通用batchUpdate方法执行结束===========");
                return  this.sqlMapClient.executeBatch();
            }
        } catch (SQLException var4) {
            var4.printStackTrace();
            throw new RuntimeException(var4.getMessage(), var4);
        }
    }

做了如上操作后,生产导入的数据时间从4min提升到了30s

课外知识------------------------------------------------

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。每个线程使用的都是自己从内存中拷贝过来的变量的副本, 这样就不存在线程安全问题,也不会影响程序的执行性能。

ThreadLocal的接口方法:ThreadLocal类接口很简单,只有4个方法,ThreadLocal 可以存储任何类型的变量对象, get返回的是一个Object对象,但是我们可以通过泛型来制定存储对象的类型。

public T get() { } // 用来获取ThreadLocal在当前线程中保存的变量副本
public void set(T value) { } //set()用来设置当前线程中变量的副本
public void remove() { } //remove()用来移除当前线程中变量的副本
protected T initialValue() { } //initialValue()是一个protected方法,一般是用来在使用时进行重写的

有兴趣的可以看这个博主写的批量更新的源码,跟着他的思路慢慢看就能理顺

ibatis 批量入库优化_getlocalsqlmapsession-CSDN博客

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值