mybaties的缓存(转)

内容大纲.png

前言

本篇意在通过Hibernate和Mybaitis缓存,通过对比学习,同时弄懂这两者中的区别

Hibernate中的缓存

Hibernate中一般常用的缓存有三个,一级缓存,二级缓存,查询缓存,要了解一二级缓存的可以点击->图解SSH-Hibernate,这里主要讲解一下二级缓存和查询缓存

首先我们先看一下Hibernate的二级缓存

Hibernate二级缓存.png

文字描述过程:

  • 首先我们get(1L)的时候,由于二级缓存中没有,所以我们就去数据库查询,并将结果返回后插入到二级缓存中,然后将结果插入到二级缓存中,并将数据返回.
  • 当我们再次查询时,由于二级缓存中已经存在了该对象,那么我们就不用到数据库中查询,直接从缓存中把结果返回

那么我们再来看看Hibernate中的查询缓存

Hibernate查询缓存.png

文字描述过程:

  • 首先list()的时候,由于查询缓存中没有,那么我们去数据库查,并将数据放在了查询缓存中,然后将结果返回
  • 当我们进行insert操作的时候,首先会给数据库增加一条数据,然后关键的地方来了,此时Hibernate会清空所有的查询缓存,因为此时数据库中的数据已经变了,如果不清空缓存,就会导致select * from User拿到的还是1L和2L,但是此时正确的应该是1L,2L,3L,所以必须清空
  • 然后我们再次list()的时候,又重复第一步的操作

从以上过程我们就可以看出,Hibernate的查询缓存的命中率的非常低的,进行新增、编辑、删除操作都会去清空查询缓存,所以一般不使用查询缓存,而是使用二级缓存.

Mybaitis中的缓存

一般我们都不说MyBatis的二级缓存,而是说MyBatis的缓存,我们先来看代码

@Test
public void testCache() throws Exception {

    SqlSession session = MybatisUtil.openSession();
    UserMapper userMapper = session.getMapper(UserMapper.class);
    User u1 = userMapper.get(1L);
    session.close();

    session = MybatisUtil.openSession();
    userMapper = session.getMapper(UserMapper.class);
    User u2 = userMapper.get(1L);
    session.close();
}

这段代码中, Mybatis一共发了两条SQL,这就好像说, Mybatis中没有二级缓存,然后我们打开Mybatis的文档一看,顿时震惊

Mybatis文档.png

这难道是骗人的,说好的默认开启缓存呢.....

其实不是的,默认确实是开启缓存的,但是我们还需要配置一点东西

UserMapper.xml

<mapper namespace="com.toby.mybatis.domain.UserMapper">
    <!--mybatis中默认是支持二级缓存的,
    要是某个对象由二级缓存,需要在mapper.xml中配置如下标签-->
    <cache/>
    ...
</mapper>

另外,对象还要实现序列化接口,否则报NotSerializableException的异常

public class User implements Serializable{
...
}

设置完毕之后,我们再来尝试insert的问题

@Test
public void testCache() throws Exception {

    SqlSession session = MybatisUtil.openSession();
    UserMapper userMapper = session.getMapper(UserMapper.class);
    User u1 = userMapper.get(1L);
    session.close();

    //insert
    session = MybatisUtil.openSession();
    userMapper = session.getMapper(UserMapper.class);
    User user = new User();
    userMapper.add(user);
    session.commit();
    session.close();

    session = MybatisUtil.openSession();
    userMapper = session.getMapper(UserMapper.class);
    User u2 = userMapper.get(1L);
    session.close();
}

此时发现,发了3条SQL,那么究竟是什么原因呢?

首先,get的底层用的是selectOne,然后selectOne又用的是用selectList,所以Mybatis是没有二级缓存的概念,他的缓存,全都是查询缓存.此时如下图

Mybatis缓存.png

看完这个图,就明白为什么get(1L)->add()->get(1L)这个过程会发3条SQL了,因为insert的时候,清空了缓存

但是就算insert,并没有影响到get(1L)的结果,但是你却把他的缓存也清空了,这明显不合理,那么我们怎么样让Mybatis中的缓存更像Hibernate中的二级缓存呢?因为目前这样的缓存实在太坑,从这过程大家应该感受得到.

那么我们可不可以这样做呢?如图:

mybatis缓存改进.png

也就是我们做了两件事

  • list由于缓存命中率低,那么我们就不加入到缓存中
  • insert我们不清空缓存

这样做,Mybatis的缓存就显得更像Hibernate中的二级缓存了,那么在代码中,我们具体是怎么实现的呢?

UserMapper.xml

<!--useCache默认是true,这里我们设置为false就是让他不使用缓存-->
<select id="list" resultType="com.toby.mybatis.domain.User" useCache="false">
  SELECT * FROM user
</select>

<!--flushCache默认为true,我们设置为false,就是让他不清空缓存-->
<insert id="add" parameterType="com.toby.mybatis.domain.User"
        useGeneratedKeys="true" keyProperty="id" keyColumn="id"
        flushCache="false">
    INSERT INTO USER (username) VALUES (#{username})
</insert>

这样之后,我们Mybatis中的缓存就更高效了

时间: 2024-09-27 22:57:54

mybaties的缓存(转)的相关文章

springMVC 缓存(入门 spring+mybaties+redis一)

使用redis之前需要咋电脑上安装redis: 使用spring+mybaties+redis的本质是扩展类   org.apache.ibatis.cache.Cache:在我们自己扩展的Cache里面使用redis的api: 一:需要引入的依赖: <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId>

使用redis做mybaties的二级缓存(2)-Mybatis 二级缓存小心使用

Mybatis默认对二级缓存是关闭的,一级缓存默认开启: 下面就说说为什么使用二级缓存需要注意: 二级缓存是建立在同一个namespace下的,如果对表的操作查询可能有多个namespace,那么得到的数据就是错误的. 举个简单的例子,订单和订单详情,orderMapper.orderDetailMapper.在查询订单详情时我们需要把订单信息也查询出来,那么这个订单详情的信息被二级缓存在orderDetailMapper的namespace中,这个时候有人要修改订单的基本信息,那就是在orde

[MyBatis]二级缓存

二级缓存: Session去执行该Mapper下的查询方法时(第一次查询),会将该查询结果存放在Mapper的二级缓存区域 Session去执行该Mapper下的查询方法时(第二次查询),会判断该Mapper下有没有缓存,如果有,则不向数据库查询,直接取缓存 Session去执行该Mapper下的commit()方法后,则清空该Mapper下的二级缓存 二级缓存与一级缓存的区别: 多个Session可以共享Mapper下的数据,二级缓存是按照Mapper的namespace划分,每一个Mappe

Mybaties第三天

1. Mybaties运行原理 2.关联查询 一对一 直接写 完整的SQL语句,在ResultMap中把所有的属性写出来. 直接写 完整的SQL语句,在ResultMap中写出一个表中的字段属性,在同一个ResultMap中的association 标签中写出另一个表的字段属性,association 中的javaType属性 是从表的类型 两个表的Mapper映射文件,各自写各自的查询SQL,各自写各自的在ResultMap,主表的Mapper映射文件的ResultMap中要写associat

Apache Ignite——新一代数据库缓存系统

Apache Ignite是一个通用的数据库缓存系统,它不仅支持所有的底层数据库系统,比如RDBMS.NoSQL和HDFS,还支持Write-Through和Read-Through.Write-Behind Caching等可选功能. Apache Ignite是一个聚焦分布式内存计算的开源项目,它在内存中储存数据,并分布在多个节点上以提供快速数据访问.此外,可选地将数据同步到缓存层同样是一大优势.最后,可以支持任何底层数据库存储同样让 Ignite成为数据库缓存的首先.

数据字典实现缓存

数据字典的好处很多比如: 1.可以减少使用表,来专门记录类型. 2.类型使用key检索,或者报表统计分析,在一定程度上相比汉字来讲,效率好得多. 3.使用缓存的数据字典.也可以减少不少的io操作. 等等.... 首先,库表设计就智者见智了.不多说.爱怎么设计就怎么设计. 完整的数据字典设计 ,需要 1.生成select 自定义标签. 2.list页面,或者get页面, 一个key转 value的标签 使用自定义标签,搭配上缓存的数据字典是最方便.最完美的解决办法, 接下来,就直接贴代码了. 一.

4.缓存控制技术

动态网站的数据都是从数据库获取而来的.所以网站的瓶颈往往就是反复连接数据库和大量的SQL语句查询的执行.由于HTTP协议是无状态性的,所以每次对页面请求都会执行相同的操作.我们可以让页面内容本身变化不大但是偶尔还是要变化的页面(例如新闻网站)缓存起来作为静态的页面,下一次再访问的时候直接访问静态的HTML页面即可. ① Smarty里面控制缓存 需要做3步工作:开启缓存,指定缓存目录,定义缓存的生命周期

Shiro缓存(十三)

使用缓存,可以解决每次访问请求都查数据库的问题.第一次授权后存入缓存. 缓存流程 shiro中提供了对认证信息和授权信息的缓存.shiro默认是关闭认证信息缓存的,对于授权信息的缓存shiro默认开启的.主要研究授权信息缓存,因为授权的数据量大. 用户认证通过. 该 用户第一次授权:调用realm查询数据库 该 用户第二次授权:不调用realm查询数据库,直接从缓存中取出授权信息(权限标识符). -------------------------------------使用ehcache缓存框架

Hibernate session缓存

一级缓存(执行代码时查看console台上的sql语句)  清空缓存 @Test public void demo03(){ //清空缓存 Session session=factory.openSession(); session.beginTransaction(); //1.查询 User user = (User)session.get(User.class, 1); System.out.println(user); //session.evitc(user) //将执行对象从一级缓存