Maison > Java > javaDidacticiel > Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?

Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?

Libérer: 2023-08-23 14:25:16
avant
882 Les gens l'ont consulté

Où fonctionne la mise en cache ?

Personnellement, je pense que le cache de premier niveau et le cache de deuxième niveau de mybatis ne sont pas une très bonne conception, je n'utilise fondamentalement pas le cache de premier niveau et le cache de deuxième niveau au travail, car. s'il est mal utilisé, cela causera beaucoup de problèmes, alors jetons un coup d'œil aujourd'hui pour voir quel est le problème ?

Dans la section précédente, nous avons présenté qu'Executor appellera StatementHandler pour exécuter SQL, qui sert de lien entre le précédent et le suivant. Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?La conception d'Executor est un modèle de décorateur typique. SimpleExecutor et ReuseExecutor sont des classes d'implémentation concrètes, tandis que CachingExecutor est une classe de décorateur.

Vous pouvez voir que la classe d'implémentation de composant spécifique a une classe parent BaseExecutor, et cette classe parent est une application typique du modèle de modèle. Les opérations d'exploitation du cache de premier niveau sont toutes dans cette classe, et la fonction spécifique de. l'exploitation de la base de données est laissée à la sous-classe Réaliser.

"Le cache de deuxième niveau est une classe de décorateur. Lorsque le cache de deuxième niveau est activé, CachingExecutor sera utilisé pour décorer la classe d'implémentation spécifique, donc lors de l'interrogation, le cache de deuxième niveau doit être interrogé en premier, puis le cache de premier niveau" Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?"Alors, quelle est la différence entre le cache de premier niveau et le cache de deuxième niveau ?"

Le cache de premier niveau

Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?
// BaseExecutor
protected PerpetualCache localCache;
Copier après la connexion

Le premier -level cache est une variable membre localCache dans BaseExecutor (pour HashMap Une simple encapsulation), donc le cycle de vie du cache de premier niveau est le même que celui de SqlSession. Si vous n'êtes pas familier avec SqlSession, vous pouvez le comparer à Connection dans JDBC. programmation, qui est une session de la base de données.

「一级缓存和二级缓存key的构建规则是一致的,都是一个CacheKey对象,因为Mybatis中涉及动态SQL等多方面的因素,缓存的key不能仅仅通过String来表示」

当执行sql的如下4个条件都相等时,CacheKey才会相等

  1. mappedStatment的id
  2. 指定查询结构集的范围
  3. 查询所使用SQL语句
  4. 用户传递给SQL语句的实际参数值

「当查询的时候先从缓存中查询,如果查询不到的话再从数据库中查询」

org.apache.ibatis.executor.BaseExecutor#queryPourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?当使用同一个SqlSession执行更新操作时,会先清空一级缓存。因此一级缓存中内容被使用的概率也很低Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?

一级缓存测试

「看到美团技术团队上关于一级缓存和二级缓存的一些测试写的挺不错的,就直接引用过来了」

原文地址:https://tech.meituan.com/2018/01/19/mybatis-cache.html 测试代码github地址:https://github.com/kailuncen/mybatis-cache-demo

接下来通过实验,了解MyBatis一级缓存的效果,每个单元测试后都请恢复被修改的数据。

首先是创建示例表student,创建对应的POJO类和增改的方法,具体可以在entity包和mapper包中查看。

CREATE TABLE `student` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(200) COLLATE utf8_bin DEFAULT NULL,
  `age` tinyint(3) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Copier après la connexion

在以下实验中,id为1的学生名称是凯伦

「实验1」

开启一级缓存,范围为会话级别,调用三次getStudentById,代码如下所示:

Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?执行结果:Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?我们可以看到,只有第一次真正查询了数据库,后续的查询使用了一级缓存。

「实验2」

增加了对数据库的修改操作,验证在一次数据库会话中,如果对数据库发生了修改操作,一级缓存是否会失效。

Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?执行结果:Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?我们可以看到,在修改操作后执行的相同查询,查询了数据库,一级缓存失效。

「实验3」

开启两个SqlSession,在sqlSession1中查询数据,使一级缓存生效,在sqlSession2中更新数据库,验证一级缓存只在数据库会话内部共享。

Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?输出如下Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?sqlSession1和sqlSession2读的时相同的数据,但是都查询了数据库,说明了「一级缓存只在数据库会话层面共享」

sqlSession2更新了id为1的学生的姓名,从凯伦改为了小岑,但sqlSession1之后的查询中,id为1的学生的名字还是凯伦,出现了脏数据,也证明了之前的设想,一级缓存只在数据库会话层面共享

「MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement,即进行如下配置」

<setting name="localCacheScope" value="STATEMENT"/>
Copier après la connexion

原因也很简单,看BaseExecutor的query()方法,当配置成STATEMENT时,每次查询完都会清空缓存Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?「看到这你可能会想,我用mybatis后没设置这个参数啊,好像也没发生脏读的问题啊,其实是因为你和spring整合了」

当mybatis和spring整合后(整合的相关知识后面还有一节)

  1. 在未开启事务的情况之下,每次查询,spring都会关闭旧的sqlSession而创建新的sqlSession,因此此时的一级缓存是没有起作用的
  2. 在开启事务的情况之下,spring使用threadLocal获取当前线程绑定的同一个sqlSession,因此此时一级缓存是有效的,当事务执行完毕,会关闭sqlSession

「当mybatis和spring整合后,未开启事务的情况下,不会有任何问题,因为一级缓存没有生效。当开启事务的情况下,可能会有问题,由于一级缓存的存在,在事务内的查询隔离级别是可重复读,即使你数据库的隔离级别设置的是提交读」

二级缓存

Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?
// Configuration
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
Copier après la connexion

「而二级缓存是Configuration对象的成员变量,因此二级缓存的生命周期是整个应用级别的。并且是基于namespace构建的,一个namesapce构建一个缓存」

「二级缓存不像一级缓存那样查询完直接放入一级缓存,而是要等事务提交时才会将查询出来的数据放到二级缓存中。」

因为如果事务1查出来直接放到二级缓存,此时事务2从二级缓存中拿到了事务1缓存的数据,但是事务1回滚了,此时事务2不就发生了脏读了吗?

「二级缓存的相关配置有如下3个」

「1.mybatis-config.xml」

<settings>
 <setting name="cacheEnabled" value="true"/>
</settings>
Copier après la connexion

这个是二级缓存的总开关,只有当该配置项设置为true时,后面两项的配置才会有效果

从Configuration类的newExecutor方法可以看到,当cacheEnabled为true,就用缓存装饰器装饰一下具体组件实现类,从而让二级缓存生效Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?「2.mapper映射文件中」mapper映射文件中如果配置了中的任意一个标签,则表示开启了二级缓存功能,没有的话表示不开启

<cache type="" eviction="FIFO" size="512"></cache>
Copier après la connexion

二级缓存的部分配置如上,type就是填写一个全类名,用来指定二级缓存的实现类,这个实现类需要实现Cache接口,默认是PerpetualCache(你可以利用这个属性将mybatis二级缓存和Redis,Memcached等缓存组件整合在一起)

org.apache.ibatis.builder.MapperBuilderAssistant#useNewCachePourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?

这个eviction表示缓存清空策略,可填选项如下

选项解释装饰器类
LRU最近最少使用的:移除最长时间不被使用的对象LruCache
FIFO先进先出:按对象进入缓存的顺序来移除它们FifoCache
SOFT软引用:移除基于垃圾回收器状态和软引用规则的对象SoftCache
WEAK弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象WeakCache

Une implémentation typique du modèle de décorateur, changer la stratégie de vidage du cache consiste à changer de décorateur. Pourquoi n'est-il pas recommandé d'utiliser le cache Mybatis de premier et deuxième niveaux ?「3.