• ibatis和mybatis中的BatchExecutor


    ibatis中的的处理方法

    spring集成了ibatis的批量提交的功能,我们只要调用API就可以了
    首先在你的dao中需要继承org.springframework.orm.ibatis.support.SqlMapClientDaoSupport
    然后在代码中调用getSqlMapClientTemplate方法, 获取SqlMapClientTemplate对象,然后做处理
     
    public void insertInfos(List<Info> records) {
            if (null == records || records.size() == 0) {
                return;
            }
            // 执行回调
            SqlMapClientTemplate sqlMapClientTemplate = iBatisDaoLS13.getSqlMapClientTemplate();
            sqlMapClientTemplate.execute(new SqlMapClientCallback() {
                // 实现回调接口
                public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                    // 开始批处理, for循环里面的sql必须一致,否则会创建新的PreparedStatement
                    executor.startBatch();
                    for (Info info : records) {
                        executor.insert(NAMESPACE + "insertAInfo", info);
                    }
                    // 执行批处理
                    executor.executeBatch();
                    return null;
                }
            });
        }

    mybatis中的的处理方法

       在程序中,有时候我们需要批量的去操作一些数据,批量的新增、修改、删除,如果是通过for循环一条记录一条记录的去更新无疑效率会比较慢。更佳的做法无疑是采用JDBC对批处理的支持。Mybatis基于JDBC对批处理的支持,也提供了进行数据的批量操作的API,BatchExecutor。下面是一段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()对应的底层代码是调用对应的Statement的addBatch()方法。那它是在什么时候执行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()时调用,在这个时候都会调用Executor的flushStatements()方法,而BaseExecutor在执行flushStatements()时最终会调用其doFlushStatements()方法。当然,我们也可以手动的调用SqlSession的flushStatements()方法,其底层实现也会调用对应的BaseExecutor的flushStatements()方法。

      @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();

        }

      }

     

           下面是一个使用Mybatis的BatchExecutor进行批量操作的示例。在示例中我们创建了一个使用BatchExecutor的SqlSession,也可以是SqlSessionTemplate,其实现了SqlSession接口,底层通过一个SqlSession代理进行相应的操作。然后在循环中一次调用对应Mapper的新增操作,相当于调用BatchExecutor的doUpdate(),最后调用SqlSession的commit()方法提交事务,在SqlSession的commit()中会调用Executor的commit(),从而导致了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();

       }

  • 相关阅读:
    IPC机制key值的各位组成
    ctrl+c,ctrl+d,ctrl+z在linux中意义
    Linux x86_64与i386区别之 —— 内存寻址
    readdir_r()读取目录内容
    memmove和memcpy
    sscanf的应用
    获取CPU频率
    盘点十个超级实用的 JS 特性
    Java 类在 Tomcat 中是如何加载的?
    Java 类在 Tomcat 中是如何加载的?
  • 原文地址:https://www.cnblogs.com/widget90/p/11611585.html
Copyright © 2020-2023  润新知