编程知识 cdmana.com

Second level cache of mybatis, using redis as secondary cache

   What is L2 cache ?

   The principle of L2 cache and L1 cache is the same , First query , Will put the data in the cache , Then the second query will go directly to the cache . But the first level cache is based on sqlSession, The second level cache is based on mapper Of documents namespace Of , That is to say, more than one sqlSession Can share one mapper The secondary cache area in the , And how about two mapper Of namespace identical , Even two mapper, Then these two mapper In the implementation of sql The query data will also be stored in the same secondary cache area

  

image-20201111211828145

 

   Pictured above sqlSession1 The query will be made from UserMapper In the second level cache , If not, perform the database query operation .

   And then write it to the L2 cache

  sqlSession2 Do the same thing UserMapper When inquiring , From UserMapper In the second level cache , At this point, there is already content in the secondary cache , So you can get it directly , No more interaction with the database .

  sqlSession3 The transaction is performing an operation ( Insert 、 to update 、 Delete ) when , It will be emptied UserMapper Second level cache of

  1. Enable L2 cache

   How to use L2 cache :

  mybatis in , The first level cache is enabled by default , But the secondary cache needs to be configured before it can be used

   In the global profile sqlMapConfig.xml Add the following code to :

  

  

  

  

   Second, which namespace The configuration of secondary level is where it is opened , because mybatis There are notes and xml Two ways, so :

   annotation

  

image-20201111221707937

 

   Annotation extension :

  // By default, we use mybatis Built in L2 cache , It is implemented in PerpetualCache Class , So it can be written as

  @CacheNamespace(implementation = PerpetualCache.class)

  // If using redis As a second level cache , The second part of this article will talk about

  xml

  

image-20201111221501041

 

   So it turns on UserMapper Second level cache of

   Test one :

   We need to be based on the user id Query user information :

  

image-20201111222635859

 

   Be careful : Will cache pojo Realization Serializable Interface , In order to extract the cache data, the deserialization operation is performed , Because the secondary cache has a variety of storage media , Not necessarily only in memory , It could be in the hard disk , If we're going to take out this cache again , You need to deserialize . therefore mybatis Of pojo To achieve Serializable Interface

  

image-20201111222950505

 

   Finally, execute to see the print log :

  

image-20201111223421674

 

   Why? System.out.println(user1==user2) by false ?

   L2 cache is different from L1 cache , The L2 cache does not cache objects , It's data , In the second query, the underlying layer recreates a User object , And the data in the secondary cache is repackaged into objects and returned . therefore user1 and user2 Not an object .

   Test two :

   Let's do a transaction operation in test two , See if you can empty the secondary cache :

  

image-20201111224352601

 

  

image-20201111224330557

 

  ​ Added a modification operation , It was found that two select, Indicates that the commit transaction will refresh the secondary cache

  userCache and flushCache

   It can also be configured userCache and flushCacheuserCache : It is used to set whether to disable the secondary cache , stay statement The settings in can disable the current select Second level caching of statements , That is to say, every query will send out sql. The default is true.

  

image-20201111225137076

 

  

image-20201111225544937

 

  flushCache : stay mapper The same namespace in , If there are other add, delete and modify operations, you need to refresh the cache , If the cache is flushed, dirty reads will appear .

   Set up statement The configuration of the flushCache="true", That is to refresh the cache , If change to false It doesn't refresh , There may be dirty reading . So in general, there is no need to change

  

image-20201111225901338

 

  Mybatis The second level cache is used as well as the first level cache org.apache.ibatis.cache.impl.PerpetualCache This class is mybatis The default cache class of , meanwhile , If you want to customize the cache, you have to implement cache Interface

  

image-20201112005725676

 

  2. Use Redis Second level cache

  Mybatis There are drawbacks to the built-in L2 cache , It's this cache that works on a single server , Can't implement distributed caching .

  

image-20201112010039059

 

   So in order to solve this problem , We have to find a distributed cache to store cache data .

  

image-20201112010027075

 

   How to use

  mybatis Provides a target for cache Interface redis Implementation class , stay mybatis-redis In bag

   First let's introduce jar package

  

  org.mybatis.caches

  mybatis-redis

  1.0.0-beta2

  

   modify Mapper.xml file

  //**********XML The way ***********:

  

  

  // For the current namespace Enable L2 cache

  

     select * from user   

  //******* Annotation mode **********

  @CacheNamespace(implementation = RedisCache .class)

  public interface UserMapper {

  // according to id Query the user Annotations use

  @Select("select * from user where id=#{id}")

  public User findById(Integer id);

   This class also implements Cache Interface

  

image-20201112011613642

 

   To configure redis Configuration file for

  redis.host=localhost

  redis.port=6379

  redis.connectionTimeout=5000

  redis.password=

  redis.database=0

   The test method is the same as the built-in L2 cache .

  3. Redis Source code analysis of L2 cache

  RedisCache and Mybatis The schemes for L2 caching are almost the same , Nothing but realization Cache Interface , And use jedis Operating the cache , But there are some differences in the design details .

   We analyze the source code with problems :

   stay RedisCache How does a class turn to redis To access the cache value ?

   What kind of data structure is used ?

  package org.mybatis.caches.redis;

  import java.util.Map;

  import java.util.concurrent.locks.ReadWriteLock;

  import org.apache.ibatis.cache.Cache;

  import redis.clients.jedis.Jedis;

  import redis.clients.jedis.JedisPool;

  // First of all, it realizes Cache Interface , By mybatis During initialization CacheBuilder establish

  // The creation method is to call the following parameter construction

  public final class RedisCache implements Cache {

  private final ReadWriteLock readWriteLock = new DummyReadWriteLock();

  private String id;

  private static JedisPool pool;

  // There are parametric structures

  public RedisCache(final String id) {

  if (id == null) {

  throw new IllegalArgumentException("Cache instances require an ID");

  }

  this.id = id;

  //RedisConfigurationBuilder call parseConfiguration() Method creation RedisConfig object

  RedisConfig redisConfig = RedisConfigurationBuilder.getInstance().parseConfiguration();

  // structure Jedis pool

  pool = new JedisPool(redisConfig, redisConfig.getHost(), redisConfig.getPort(),

  redisConfig.getConnectionTimeout(), redisConfig.getSoTimeout(), redisConfig.getPassword(),

  redisConfig.getDatabase(), redisConfig.getClientName());

  }

  // Template method , Below putObject and getObject、removeObject It's used in this way

  private Object execute(RedisCallback callback) {

  Jedis jedis = pool.getResource();

  try {

  return callback.doWithRedis(jedis);

  } finally {

  jedis.close();

  }

  }

  //........ Omitted code

  @Override

  public void putObject(final Object key, final Object value) {

  execute(new RedisCallback() {

  @Override

  public Object doWithRedis(Jedis jedis) {

  jedis.hset(id.toString().getBytes(), key.toString().getBytes(), SerializeUtil.serialize(value));

  return null;

  }

  });

  }

  @Override

  public Object getObject(final Object key) {

  return execute(new RedisCallback() {

  @Override

  public Object doWithRedis(Jedis jedis) {

  return SerializeUtil.unserialize(jedis.hget(id.toString().getBytes(), key.toString().getBytes()));

  }

  });

  }

  @Override

  public Object removeObject(final Object key) {

  return execute(new RedisCallback() {

  @Override

  public Object doWithRedis(Jedis jedis) {

  return jedis.hdel(id.toString(), key.toString());

  }

  });

  }

  }

  RedisConfig redisConfig = RedisConfigurationBuilder.getInstance().parseConfiguration();

  

image-20201112014625885

 

  RedisConfig The default Redis Configuration information   Zhengzhou infertility hospital which good -36 The age of 1 Successful baby holding in months :https://yyk.fh21.com.cn/hospital_6369/tsyl/16697496.html

  

image-20201112014920980

 

   This method reads our configuration in /resource/redis.properties This file

  RedisConfig After that, we built Jedis pool    Zhengzhou infertility hospital introduced pregnant history women affect pregnancy :https://yyk.fh21.com.cn/hospital_6369/tsyl/16697499.html

  put Method

  private Object execute(RedisCallback callback) {

  Jedis jedis = pool.getResource();

  try {

  return callback.doWithRedis(jedis);

  } finally {

  jedis.close();

  }

  }

  public void putObject(final Object key, final Object value) {

  execute(new RedisCallback() {

  @Override

  public Object doWithRedis(Jedis jedis) {

  jedis.hset(id.toString().getBytes(), key.toString().getBytes(), SerializeUtil.serialize(value));

  return null;

  }

  });

  }

   We can see ,put Method calls the template method to get One jedis link , And then call doWithRedis() Method

  jedis.hset(id.toString().getBytes(), key.toString().getBytes(), SerializeUtil.serialize(value));

   You can see it clearly ,mybatis-redis When storing data , It is used. hash structure , hold cache Of id As this hash Of key (cache Of id stay mybatis The middle is mapper Of namespace); This mapper Query cache data in as hash Of field, What needs to be cached is used directly SerializeUtil Storage ,SerializeUtil Similar to other serialization classes , Responsible for the serialization and deserialization of objects ;

版权声明
本文为[Procedure monkey 1Jia]所创,转载请带上原文链接,感谢

Scroll to Top