津爱改装车|来,全搞懂,原来Mybatis执行一个sql有这么多类型,绝( 二 )


示例代码上面一样 , 只是把 SimpleExecutor 换成 ReuseExecutor。从执行我们看到 , Preparing 只有一次 , 执行结果也是正确的:
[DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==>Preparing: select * from `user` where id = ? [DEBUG][main] m.p.ThresholdInterceptor.intercept ThresholdInterceptor plugin... [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==> Parameters: 1(Integer) [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug <==Total: 1 [DEBUG][main] m.p.ThresholdInterceptor.intercept ThresholdInterceptor plugin... [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==> Parameters: 1(Integer) [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug <==Total: 1 他是怎么做到的呢?翻开代码看看实现 , 其实逻辑也很简单 , 用 SQL 当作 key 保存对应的 Statement 来实现重用 。
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {Statement stmt;BoundSql boundSql = handler.getBoundSql();String sql = boundSql.getSql();// 关键逻辑 , 通过 sql 判断是否已经创建了 Statement , 如果有则重用 。if (hasStatementFor(sql)) {stmt = getStatement(sql);applyTransactionTimeout(stmt);} else {Connection connection = getConnection(statementLog);stmt = handler.prepare(connection, transaction.getTimeout());putStatement(sql, stmt);}handler.parameterize(stmt);return stmt;}private final Map statementMap = new HashMap<>();private boolean hasStatementFor(String sql) {try {Statement statement = statementMap.get(sql);return statement != null} catch (SQLException e) {return false;}}BatchExecutor有些场景下 , 我们要批量保存或者删除 , 更新数据 , 这时候我们一条一条的执行效率就会很低 , 需要一个批量执行的机制 。
JDBC 批量操作批量操作可以把相关的sql打包成一个 batch , 一次发送到服务器 , 减少和服务器的交互 , 也就是 RTT 时间 。
使用批量操作前要确认服务器是否支持批量操作 , 可通过 DatabaseMetaData.supportsBatchUpdates() 方法的返回值来判断 。
实例代码 , 通过 JDBC 提供的 API 执行批量操作 。
Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);DatabaseMetaData metaData = http://kandian.youth.cn/index/conn.getMetaData();System.out.println("metaData.supportsBatchUpdates() = " + metaData.supportsBatchUpdates());//执行 sqlSystem.out.println("Creating statement...");String sql = "update user set name=? where id = ?";pstmt = conn.prepareStatement(sql);// 设置变量pstmt.setString(1, "Pappu");pstmt.setInt(2, 1);// 添加到 batchpstmt.addBatch();// 设置变量pstmt.setString(1, "Pawan");pstmt.setInt(2, 2);// 添加到 batchpstmt.addBatch();//执行 , 并获取结果int[] count = pstmt.executeBatch();Mybatis 如何实现Mybatis 只有对 update 有支持批量操作 , 并且需要手动 flushStatements 。
insert、delete、update , 都是update操作
BatchExecutor batchExecutor = new BatchExecutor(configuration, jdbcTransaction);final MappedStatement update = configuration.getMappedStatement("dm.UserMapper.updateName");final MappedStatement delete = configuration.getMappedStatement("dm.UserMapper.deleteById");final MappedStatement get = sessionFactory.getConfiguration().getMappedStatement("dm.UserMapper.getUserByID");final MappedStatement insertUser = sessionFactory.getConfiguration().getMappedStatement("dm.UserMapper.insertUser");// querybatchExecutor.doUpdate(insertUser, new User().setName("" + new Date()));batchExecutor.doUpdate(insertUser, new User().setName("" + new Date()));// batch updateUser user = new User();user.setId(2);user.setName("" + new Date());batchExecutor.doUpdate(update, user);user.setId(3);batchExecutor.doUpdate(update, user);batchExecutor.doUpdate(insertUser, new User().setName("" + new Date()));//final List batchResults = batchExecutor.flushStatements(false);jdbcTransaction.commit();printBatchResult(batchResults);