mybatis二级缓存问题

a:focus {
outline: thin dotted #333;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
a:hover {
outline: 0;
}
a:active {
outline: 0;
}
a:hover {
color: #005580 !important;
text-decoration: underline !important;
}
blockquote small:before {
content: ‘\2014 \00A0‘;
}
q:before {
content: "";
}
q:after {
content: "";
}
blockquote:before {
content: "";
}
blockquote:after {
content: "";
}

mybatis二级缓存问题

mybatis

缓存

1、mybatis缓存中的问题:

在使用mybatis进行关联查询的时候,如果学生和老师两张表进行关联查询有一下的操作步骤:

1.1 通过学生进行关联查询老师Mapper文件为:

  <select id="queryStudentAndTeacher" resultMap="BaseResultMap" useCache="true" >
    SELECT
        s.id,
        s.`name`,
        s.gender,
        s.major,
        s.grade,
        s.supervisor_id ,
        t.id as tea_id,
        t.`name` as tea_name,
        t.gender as tea_gender,
        t.research_area  as tea_research_area,
        t.title  as tea_title
    FROM
        student s
    LEFT JOIN teacher t ON s.supervisor_id = t.id
  </select>

1.2 查询完成后我更新了老师

  <update id="updateByExample" parameterType="map" >
    update teacher
    set id = #{record.id,jdbcType=INTEGER},
      name = #{record.name,jdbcType=VARCHAR},
      gender = #{record.gender,jdbcType=VARCHAR},
      research_area = #{record.researchArea,jdbcType=VARCHAR},
      title = #{record.title,jdbcType=VARCHAR}
    <if test="_parameter != null" >
      <include refid="Update_By_Example_Where_Clause" />
    </if>
  </update>

1.3 再次查询:

我们发现更新了数据,但是查询出的结果却没有变化

    @Test
    public void TestSecondCache() throws IOException{
        org.apache.ibatis.logging.LogFactory.useStdOutLogging();
        Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(reader);
        reader.close();
        SqlSession session = null;
        session = sqlSessionFactory.openSession();
        StudentMapper studentMapper = (StudentMapper) session.getMapper(StudentMapper.class);
        Map<String, Object> params = new HashMap<String,Object>();
        /**
         * 模拟下面的情况
         * 1. 执行StudentMapper中的"queryStudentAndTeacher" 操作,此时会将查询到的结果放置到StudentMapper对应的二级缓存StudentCache中;
         * 2. 执行teacherMapper中对teacher的更新操作(update、delete、insert)后,teacher的数据更新;
         * 3. 再执行1完全相同的查询,这时候会直接从StudentMapper二级缓存StudentCache中取值,将StudentMapper中的值直接返回;
         * */
        List<Student> students = studentMapper.queryStudentAndTeacher(params);
        for (Student student : students) {
            System.out.println(student.getId() + student.getTeacher().getName());
        }
        System.out.println(students.size());

        //更新老师
        SqlSession session2 = sqlSessionFactory.openSession();
        TeacherMapper teacherMapper = session2.getMapper(TeacherMapper.class);
        Teacher teacher = new Teacher();
        teacher.setName("刘老师");
        teacher.setId(1);
        TeacherExample teacherExample = new TeacherExample();
        teacherExample.createCriteria().andIdEqualTo(1);
        teacherMapper.updateByExample(teacher, teacherExample);
        session2.commit();

        //第二次查询,查看是否从缓存中读取
        List<Student> students2 = studentMapper.queryStudentAndTeacher(params);
        for (Student student : students2) {
            System.out.println(student.getId() + student.getTeacher().getName());
        }
        System.out.println(students2.size());
        checkCacheStatus(session);
    }

2、 如果遇到这种情况,应该如何解决?

我们可以上网,网上提供的二级缓存插件来解决该问题:

简介

MyBatis Enhanced Cache, Control your Caches precisely!

该插件主要是为了弥补MyBatis二级缓存控制上的不足,提高二级缓存Cache和数据库数据的同步性和一致性,处理各个Cache之间的关联关系。

该插件可以精确地管理MyBatis的二级缓存,实现对MyBatis二级缓存细粒度的控制。

当执行过对数据库表的更新操作(update、delete、insert)时,可以指定清除由特定的StatementId表示的查询语句产生的缓存。

应用场景:

当前的MyBaits对于缓存的比较粗糙,一般为一个Mapper配置一个Cache缓存,或者多个Mapper共用一个缓存。

而对缓存的维护都是独立的,缓存之间不会相互影响,指定的Mapper中的语句只会影响到该Mapper对应的Cache缓存。

有时候希望当执行某些更新操作时,能够刷新或者清空特定的查询语句产生的缓存,以避免数据不一致的情况。

###举例



现有AMapper.xml 中定义了对数据库表ATable的CRUD操作,BMapper定义了对数据库表BTable的CRUD操作;

假设MyBatis的二级缓存开启,并且AMapper中使用了二级缓存,AMapper对应的二级缓存为ACache

除此之外,AMapper中还定义了一个跟BTable有关的查询语句,类似如下所述:

<select id="selectATableWidtJoin" resultMap="BaseResultMap" useCache="true">
      select * from ATable left join BTable on ....
</select>
  1. 执行了selectATableWithJoin操作,该查询的缓存会被放置到对应的二级缓存ACache中,

    当再次执行相同的查询,则直接从二级缓存ACache中;

  2. 如果某个时候,BMapper中执行了对BTable的update操作(update 、delete、insert),BTable 的数据已经更新,
  3. 再次执行selectATableWithJoin操作,该查询的结果直接从二级缓存ACache中取,这时候就造成了**数据不一致**的情况

针对上述的问题,需要解决

当BMapper执行对BTable的update操作时,指定刷新 ACache中的 selectATableWithJoin语句产生的缓存

该插件正是解决上述的这一问题!

使用方法:

使用此插件非常简单:

  1. 在mybatisConfig.xml 文件中定义plugin节点如下:
  <plugins>
       <plugin interceptor="org.luanlouis.mybatis.plugin.cache.EnhancedCachingExecutor">
          <property name="dependency" value="dependencys.xml"/>
          <property name="cacheEnabled" value="true"/>
       </plugin>
  </plugins>
  1. dependencys.xml配置文件,配置StatemntId依赖关系
<?xml version="1.0" encoding="UTF-8"?>
<dependencies>
   <statements>
       <statement id="com.louis.mybatis.dao.DepartmentsMapper.updateByPrimaryKey">
          <observer id="com.louis.mybatis.dao.EmployeesMapper.selectWithDepartments" />
       </statement>
   </statements>
</dependencies>
  • <statement>节点配置更新语句和查询语句的依赖关系,如果id表示的更新语句执行了,会清空由配置的id表示的查询语句生成的缓存。
  • <observer>节点表示当父节点 id表示的更新语句执行后,应该清除此语句所产生的缓存
时间: 2024-10-04 10:01:41

mybatis二级缓存问题的相关文章

深入了解MyBatis二级缓存

深入了解MyBatis二级缓存 标签: mybatis二级缓存 2015-03-30 08:57 41446人阅读 评论(13) 收藏 举报  分类: Mybatis(51)  版权声明:版权归博主所有,转载请带上本文链接!联系方式:[email protected] 目录(?)[+] 深入了解MyBatis二级缓存 一.创建Cache的完整过程 我们从SqlSessionFactoryBuilder解析mybatis-config.xml配置文件开始: Reader reader = Reso

MyBatis二级缓存配置

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 Mybatis二级缓存是SessionFactory,如果两次查询基于同一个SessionFactory,那么就从二级缓存中取数据,而不用到数据库里去取了. 1. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空. 2. 二级缓存与一级缓存其机制相同,默认也是采用

如何细粒度地控制你的MyBatis二级缓存(mybatis-enhanced-cache插件实现)

前几天网友chanfish 给我抛出了一个问题,笼统地讲就是如何能细粒度地控制MyBatis的二级缓存问题,酝酿了几天,觉得可以写个插件来实现这个这一功能.本文就是从问题入手,一步步分析现存的MyBatis的二级缓存的不足之处,探讨一点可以改进的地方,并且对不足之处开发一个插件进行弥补. 本文如下组织结构: 一个关于MyBatis的二级缓存的实际问题 当前MyBatis二级缓存的工作机制 mybatis-enhanced-cache插件的设计和工作原理 mybatis-enhanced-cach

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

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

Mybatis二级缓存的简单应用

1.接口 public interface MemberMapperCache { public Members selectMembersById(Integer id); } 2.POJO类 实现序列化接口 public class Members implements Serializable { private static final long serialVersionUID = 1L; private Integer id; private String member_name;

mybatis二级缓存详解

1  二级缓存简介 二级缓存是在多个SqlSession在同一个Mapper文件中共享的缓存,它是Mapper级别的,其作用域是Mapper文件中的namespace,默认是不开启的.看如下图: 整个流程是这样的(不考虑第三方缓存库): 当开启二级缓存后,在配置文件中配置<setting name="cacheEnabled" value="true"/>这行代码,Mybatis会为SqlSession对象生成Executor对象时,还会生成一个对象:C

[MyBatis]二级缓存

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

myBatis学习(9):一级缓存和二级缓存

正如大多数持久层框架一样,MyBatis同样提供了一级缓存和二级缓存的支持 1. MyBatis一级缓存基于PerpetualCache的HashMap本地缓存,其存储作用域为 Session,默认情况下,一级缓存是开启状态的.当 Session flush(); 或 close(); 之后,该Session中的所有 Cache 就将清空. 2.MyBatis二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Nam

mybatis结合redis实战二级缓存(六)

之前的文章中我们意见分析了一级缓存.二级缓存的相关源码和基本原理,今天我们来分享下了mybatis二级缓存和redis的结合,当然mybatis二级缓存也可以和ehcache.memcache.OSCache.Hazelcast结合使用.二级缓存相关的源码分享请参考<Mybatis源码分析之Cache二级缓存原理>.我们通过两种方式来实战,一种是自己编写缓存.另外一种是官方给出的demo地址:http://www.mybatis.org/redis-cache/ 一:自定义mybatis缓存