Mybatis的Executor介绍(二)——批处理,批量更新-阿里云开发者社区

开发者社区> elim1> 正文

Mybatis的Executor介绍(二)——批处理,批量更新

简介: 6       Mybatis的Executor介绍(二)——批处理        在程序中,有时候我们需要批量的去操作一些数据,批量的新增、修改、删除,如果是通过for循环一条记录一条记录的去更新无疑效率会比较慢。
+关注继续查看

6       MybatisExecutor介绍(二)——批处理

       在程序中,有时候我们需要批量的去操作一些数据,批量的新增、修改、删除,如果是通过for循环一条记录一条记录的去更新无疑效率会比较慢。更佳的做法无疑是采用JDBC对批处理的支持。Mybatis基于JDBC对批处理的支持,也提供了进行数据的批量操作的APIBatchExecutor。下面是一段JDBC进行批量操作的示例代码。

   @Test

   public void testJDBCBatch() throws SQLException {

      String sql = "insert into t_user(name, mobile, email) values(?,?,?)";

      try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql);) {

        List<User> users = this.getUsers();

        for (User user : users) {

           pstmt.setString(1, user.getName());

           pstmt.setString(2, user.getMobile());

           pstmt.setString(3, user.getEmail());

           pstmt.addBatch();

        }

        pstmt.executeBatch();

        conn.commit();

      }

   }

 

       在每一次调用的时候是调用Statement.addBatch()方法,最终所有的参数都传递完了,没有更多的参数时调用Statement.executeBatch()方法进行批量操作。在上一篇博文中我们查看了BatchExecutor的源码,它的核心代码doUpdate()方法,每次被调用的时候都是以handler.batch()结束,而handler.batch()对应的底层代码是调用对应的StatementaddBatch()方法。那它是在什么时候执行executeBatch()呢?

  @Override

  public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {

    final Configuration configuration = ms.getConfiguration();

    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);

    final BoundSql boundSql = handler.getBoundSql();

    final String sql = boundSql.getSql();

    final Statement stmt;

    if (sql.equals(currentSql) && ms.equals(currentStatement)) {

      intlast = statementList.size() - 1;

      stmt = statementList.get(last);

     handler.parameterize(stmt);//fix Issues 322

      BatchResult batchResult = batchResultList.get(last);

      batchResult.addParameterObject(parameterObject);

    } else {

      Connection connection = getConnection(ms.getStatementLog());

      stmt = handler.prepare(connection);

      handler.parameterize(stmt);    //fix Issues 322

      currentSql = sql;

      currentStatement = ms;

      statementList.add(stmt);

      batchResultList.add(new BatchResult(ms, sql, parameterObject));

    }

  // handler.parameterize(stmt);

    handler.batch(stmt);

    return BATCH_UPDATE_RETURN_VALUE;

  }

 

       它的executeBatch()是在doFlushStatements()方法调用中调用的,它会在当前Executor进行commit时调用,也会在当前Executor第一次执行doQuery()时调用,在这个时候都会调用ExecutorflushStatements()方法,而BaseExecutor在执行flushStatements()时最终会调用其doFlushStatements()方法。当然,我们也可以手动的调用SqlSessionflushStatements()方法,其底层实现也会调用对应的BaseExecutorflushStatements()方法。

  @Override

  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {

    try {

      List<BatchResult> results = new ArrayList<BatchResult>();

      if (isRollback) {

        return Collections.emptyList();

      }

      for (int i = 0, n = statementList.size(); i < n; i++) {

        Statement stmt = statementList.get(i);

        BatchResult batchResult = batchResultList.get(i);

        try {

          batchResult.setUpdateCounts(stmt.executeBatch());

          MappedStatement ms = batchResult.getMappedStatement();

          List<Object> parameterObjects = batchResult.getParameterObjects();

          KeyGenerator keyGenerator = ms.getKeyGenerator();

          if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {

            Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;

            jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);

          } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141

            for (Object parameter : parameterObjects) {

              keyGenerator.processAfter(this, ms, stmt, parameter);

            }

          }

        } catch (BatchUpdateException e) {

          StringBuilder message = new StringBuilder();

          message.append(batchResult.getMappedStatement().getId())

              .append(" (batch index #")

              .append(i + 1)

              .append(")")

              .append(" failed.");

          if (i > 0) {

            message.append(" ")

                .append(i)

                .append(" prior sub executor(s) completed successfully, but will be rolled back.");

          }

          throw new BatchExecutorException(message.toString(), e, results, batchResult);

        }

        results.add(batchResult);

      }

      return results;

    } finally {

      for (Statement stmt : statementList) {

        closeStatement(stmt);

      }

      currentSql = null;

      statementList.clear();

      batchResultList.clear();

    }

  }

 

       下面是一个使用MybatisBatchExecutor进行批量操作的示例。在示例中我们创建了一个使用BatchExecutorSqlSession,也可以是SqlSessionTemplate,其实现了SqlSession接口,底层通过一个SqlSession代理进行相应的操作。然后在循环中一次调用对应Mapper的新增操作,相当于调用BatchExecutordoUpdate(),最后调用SqlSessioncommit()方法提交事务,在SqlSessioncommit()中会调用Executorcommit(),从而导致了executeBatch()的发生。

   @Test

   public void testExecutor() {

      SqlSession session = this.sessionFactory.openSession(ExecutorType.BATCH);

      UserMapper mapper = session.getMapper(UserMapper.class);

      User user = null;

      for (inti = 0; i < 10; i++) {

        user = new User();

        user.setName("Name_" + i);

        user.setEmail("email");

        mapper.insert(user);

      }

      // 批量插入User

      session.commit();// 提交事务时批量操作才会写入数据库

      session.close();

   }

 

参考文档

       Mybatis源码

 

(注:本文是基于Mybatis3.3.1所写,写于20161224日星期六)

 

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
批处理bat文件的写作教程及实例
怎么写批处理bat文件echo、@、call、pause、rem(小技巧:用::代替rem)是批处理文件最常用的几个命令。echo 表示显示此命令后的字符 echo off 表示在此语句后所有运行的命令都不显示命令行本身 @与echo off相象,但它是加在每个命令行的最前面,表示运行时不显示这一行的命令行(只能影响当前行)。
720 0
windows下bat批处理实现守护进程
本文转自网络,由于找不到原作者,因而无法知道出处。如果有幸让原作者看到,请联系我加上。先转载至此。 最近几天加班加疯掉了,天天晚上没法睡。开发部的一个核心程序总是会自己宕机,然后需要手工去起,而这个服务的安全级别又很高,只有我可以操作,搞得我晚上老没法睡,昨晚实在受不了了,想起以前在hp-ux下写的shell守护进程,这回搞个windows下的bat版守护程序吧,当时晚上思路已经很迟钝了,就叫了个兄弟让他写了,上去后运行效果不错,至少昨晚我安心睡了7小时。
451 0
Fescar - RM BaseTransactionalExecutor介绍
开篇  这篇文章的目的是讲解RM Executor模块当中一些通用的方法,这些方法在各个Executor的父类当中实现的,各个子类Executor模块都会复用,因此抽取出来统一的进行讲解。  个人是认为抽取通用的内容放在一篇文章讲解完后可以针对每类Executor讲解特有的功能,这样能够有更好的理解。
932 0
使用mybatis对数据库执行更新操作时,parameterType为某个具体的bean,而bean中传入的参数为null时,抛出异常
使用mybatis对数据库执行更新操作时,parameterType为某个具体的bean,而bean中传入的参数为null时,抛出异常 问题描述 在使用mybatis对数据库执行更新操作时,parameterType为某个具体的bean,而bean中传入的参数为null时,抛出异常如下:org.
1645 0
带你读《跟老男孩学Linux运维:核心基础篇(上)(第2版)》之二:Linux系统介绍与环境搭建准备
本书是一本以企业Linux运维需要的知识为基础的实战型教学图书,书的内容并非大而全,但处处可以体现实战二字,非常多的内容取自于企业实战案例,并结合老男孩十几年的运维经验和教学经验进行梳理。
1115 0
Mybatis的Executor介绍(二)——批处理,批量更新
6       Mybatis的Executor介绍(二)——批处理        在程序中,有时候我们需要批量的去操作一些数据,批量的新增、修改、删除,如果是通过for循环一条记录一条记录的去更新无疑效率会比较慢。
1392 0
+关注
elim1
喜欢研究技术的码农
258
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载