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

执行日志:
[DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==>Preparing: insert into `user` (name) values(?); [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==> Parameters: Sat Jul 04 15:07:30 CST 2020(String) [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==> Parameters: Sat Jul 04 15:07:30 CST 2020(String) [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==>Preparing: update `user` set name=? where id = ? [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==> Parameters: Sat Jul 04 15:07:30 CST 2020(String), 2(Integer) [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==> Parameters: Sat Jul 04 15:07:30 CST 2020(String), 3(Integer) [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==>Preparing: insert into `user` (name) values(?); [DEBUG][main] o.a.i.l.j.BaseJdbcLogger.debug ==> Parameters: Sat Jul 04 15:07:30 CST 2020(String) [DEBUG][main] o.a.i.t.j.JdbcTransaction.commit Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4b3ed2f0] 第 1 个结果[1, 1]第 2 个结果[1, 1]第 3 个结果[1]从日志可以看到看到清晰的执行过程 。

  • 第一个insert语句后面跟着两个参数 , 是一个statement 。 对应第 1 个结果
  • 第二个update语句后面跟着两个参数 , 是一个statement 。 对应第 2 个结果
  • 第三个insert语句后面跟着两个参数 , 是一个statement 。 对应第 3 个结果
整体逻辑和程序是一致的 , 但是有个问题 , 为什么三个相同的 insert , 会分开两个结果返回呢?
这是因为 Mybatis 为了保证批次和逻辑顺序一致做了优化 , 并不是相同的sql就放到相同的statement 。 而是要按照执行顺序把相同的sql当作一个批次 。
从代码中可以看到这部分逻辑:
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {if (sql.equals(currentSql) && ms.equals(currentStatement)) {使用当前的 statement} else {创建新的statement}}总结网络上有些文章介绍使用 foreach 的方式执行批量操作 , 我个人不建议这样操作 。
  1. 因为 JDBC 已经提供了批量操作的接口 , 符合规范 , 兼容性和性能更好 。
  2. foreach拼接的 sql 比较长 , 会增加网络流量 , 而且驱动对sql长度是有限制的 , 并且要增加allowMultiQueries参数 。
  3. foreach 拼接的 sql 每次都不一定相同 , 服务器会重新编译 。
Mysql 的 sql 执行流程是连接器 , 查询缓存 , 分析器 , 优化器 , 执行器 。 分析器先会做“词法分析” 。 优化器是在表里面有多个索引的时候 , 决定使用哪个索引;或者在一个语句有多表关联(join)的时候 , 决定各个表的连接顺序 。 在适合的场景使用 ReuseExecutor 或 BatchExecutor 不仅可以提高性能 , 还可以减少对 Mysql 服务器的压力 。
【津爱改装车|来,全搞懂,原来Mybatis执行一个sql有这么多类型,绝】作者:但莫链接:来源:掘金


推荐阅读