statement 一次执行多条sql_MyBatis#基础执行器与一级缓存处理(二)

首先回顾一下(一)的内容

重用执行器 Reuse Executor

Q:一个SqlSession执行了selectList和selectOne,两个的sql语句都相同,是否可以命中Statement的缓存?

fd45a6670ecb00ed837499a3424596f2.png

A:可以命中缓存

所命中的缓存是JDBC中的ReuseStatement的PrepareStatement的缓存,不是一级缓存,只要最终的SQL语句一样就会命中Statement

UserMapper:

@CacheNamespace
public interface UserMapper {
    

    //两个SQL一样
    @Select({
    " select * from users where id=#{1}"})
    User selectByid(Integer id);


    @Select({
    " select * from users where id=#{1}"})
    User selectByid3(Integer id);
}

    @Test
    public void sessionByReuseTest(){
    
        SqlSession sqlSession = factory.openSession(ExecutorType.REUSE, true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //两个select对应两个不同的 MappedStatement 映射,会不会采用一个预处理器Statement?
        //(JDBC的Statement)
        mapper.selectByid(10);
        mapper.selectByid3(10);

    }
题目所说的Statement指的是JDBC的Statement

bc0c92094ce984f60bc83e1de7482836.png

可以看到只引入了一次预编译

如果说两个SQL不一样

@CacheNamespace
public interface UserMapper {
    

    //两个SQL一样
    @Select({
    " select * from users where id=#{1}"})
    User selectByid(Integer id);


    @Select({
    " select * from users where id=#{1} and 1=1"})
    User selectByid3(Integer id);
}

    
    
//重用执行器
@Test
public void sessionByReuseTest(){
    
    SqlSession sqlSession = factory.openSession(ExecutorType.REUSE, true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //两个select对应两个不同的 MapperStatement,不会会采用一个预处理器Statement?
    mapper.selectByid(10);
    mapper.selectByid3(10);
}

e872572b0cdebcbc2cbf3327ce375411.png

可以看到引入了两次预编译

结论:只要是SQL语句相同,就会重复利用Statement,不论是doQuery还是doUpdate最终都还是会重复的使用Statement

查看源代码可以看到:

bd6050e5a872205dd864deae22ff1495.png
String是他的SQL语句
Statement就是他缓存的JDBC的Statement

查看doQuery源码

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        //预编译SQL语句
        Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
        return handler.query(stmt, resultHandler);
    }

在预编译过程prepareStatement中(对应jdbc中的prepareStatement)

b7c1e4ea82ea126ac8165b40c5dbfe5f.png
如果没有就通过StatementHandler构建一个新的Statement,之后put进缓存中

总结:在会话期间内,所有相同的SQL语句会采用同样的Statement,只有会话结束之后Statement才会一起关闭

批处理执行器

bcc4ae07b0967f98bab72a8ab626a507.png
会话把所有的请求都发往Batch Executor,而Batch Executor会把所有的SQL语句保存起来到Statement集合中(缓存),等到flushStatement时一起进行处理(所有的增删改同时进行处理,不管StatementID是否一样),但是不一定都采用同一个Statement
@Test
public void sessionBatchTest(){
    
    SqlSession sqlSession = factory.openSession(ExecutorType.BATCH,true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    mapper.setName(10,"道友友益永存");
    mapper.addUser(Mock.newUser());

    sqlSession.flushStatements();
}

Q:是否会使用同一个JDBC Statement?

A:不是同一个Statement

Q:set和add操作是一起提交的么?

A:是一起提交的

验证:此时断点查看

7097c3cfc0d35ebaf808eb37e6e6013f.png

此时数据还没有提交

593bf32b7a546ec24bd9c98dd983678a.png

继续执行后查看数据库

be067e0f5659d50a3cd3d8d430a4f64d.png
在我们调用setName和
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值