zoukankan      html  css  js  c++  java
  • mybatis缓存学习笔记

    mybatis有两级缓存机制,一级缓存默认开启,可以在手动关闭;二级缓存默认关闭,可以手动开启。一级缓存为线程内缓存,二级缓存为线程间缓存。

    一提缓存,必是查询。缓存的作用就是查询快。写操作只能使得缓存失效,不管是一级缓存还是二级缓存,一旦发生写操作,缓存就要清空一次。

    缓存是把双刃剑,用得好比较难,用不好就把自己伤着了。

    Perpetual这个单词,意为“永恒”。PerpetualCache表示永不过期的缓存。mybatis的两级缓存都是默认为PerpetualCahe,一级缓存的缓冲机制不能更改,二级缓存的缓冲定制性非常强。可以自定义存储源(存储源其实就相当于一个HashMap,把查询跟查询结果一一对应起来)。

    一级缓存默认开启,它的实现为PerpetualCache,作用范围为Session,对于同一个Session,如果查询同一个事物查询两次,那么只执行一次数据库操作。它的清空条件有如下三种:

    * 写操作

    * 手动执行SqlSession#clearCache()

    * SqlSession#close()关闭之后缓存当然要清空,所以数据库连接池不会发生Session之间共享一级缓存的情况。

    二级缓存默认关闭,需要手动开启。它的作用域为mapper,是多线程之间共享的缓存,是应用级缓存,多个Session可以共用同一个mapper的缓存,每一个mapper维护一份缓存对象,但是可以配置多个mapper共用一份缓存对象,通过cache-ref标签。

    二级缓存粒度十分精细:

    * 全局总开关<settings>中设置cacheEnabled=true则开启二级缓存

    * mapper有cache属性

    * 语句的useCache=true

    缓存机制使用顺序:二级缓存->一级缓存->数据库

    二级缓存的选择:

    * mybatis自带的缓存

    * 用户自定义

    * 第三方内存缓存库集成

    二级缓存注意事项:

    * 在数据库中一旦使用触发器,缓存里面有可能得不到相应的更新,有可能造成数据库里更新了很多,内存里面缓存浑然不知,所以触发器与缓存悠着点用,除非十分确定二者不会互相干扰。

    * 对于同一个表的写操作和读操作必须定义在同一个mapper中(同一个namespace中),假如分开成读mapper和写mapper,那么写操作之后无法清空读mapper,缓存变成脏数据。

    * 如果一个数据库表对应一个mapper,对一个表的写操作不能直接执行对其它表的写操作(必须经过其他表的mapper来执行写操作),否则其他表的缓存可能变成脏数据。

    * csdn上一位大神说目前mybatis的缓存机制就是垃圾,根本不可用。

    一级缓存测试:

    在数据库中创建表test

    CREATE TABLE `test` (
       `id` int(11) NOT NULL AUTO_INCREMENT,
       `name` varchar(20) DEFAULT NULL,
       PRIMARY KEY (`id`)
     ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4

    插入a,b,c,d四条数据

    interface H {
        @Select("select name from test")
        List<String> get();
    }
    public class Main {
        public static void main(String[] args) {
            SqlSession session = Util.sessionFactory.openSession();
            H h = session.getMapper(H.class);
            List<String> a = h.get();
            for (int i = 0; i < a.size(); i++) {
                a.set(i, a.get(i) + " haha");
            }
            System.out.println(a.stream().collect(Collectors.joining(",")));
            a = h.get();
            a.stream().forEach(System.out::println);
            session.close();
        }
    }

    第一次查询结果没有后缀’haha‘,第二次查询有后缀’haha‘。这表明第二次使用了缓存,第一次查询之后所得到的List<String>跟缓存中的List<String>是同一个对象。所以如果使用一级缓存,对查询结果不能进行修改;也可以不使用一级缓存了,禁用之,通过把localCacheScope设为语句级别的,默认为SESSION,表示session级别的。

     <setting name="localCacheScope" value="STATEMENT"/>
  • 相关阅读:
    本地发送博客
    0.查看Android framework源码
    flutter_5_深入_2_深入layout、paint流程
    flutter_5_深入_1_深入widget树和构建流程
    flutter_5_深入_0_每帧的处理流程简介
    蓝牙基础
    Android低功耗蓝牙开发
    flutter2_widget_3布局类组件1
    flutter2_widget_1简介
    Android gradle Plugin
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/5469046.html
Copyright © 2011-2022 走看看