mybatis集成redis作为二级缓存
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis集成redis作为二级缓存相关的知识,希望对你有一定的参考价值。
mybatis默认开启了二级缓存功能,在mybatis主配置文件中,将cacheEnabled设置成false,则会关闭二级缓存功能
<settings> <!--二级缓存默认开启,false关闭--> <setting name="cacheEnabled" value="false" /> <!--mybatis日志打印到控制台--> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings>
mybatis框架虽然默认开启了二级缓存功能,但是并没有默认实现,也就是下面这句代码返回null, 然后走一级缓存
下面是配置Redis作为mybatis的二级缓存,代码如下:
(1)mybatis主配置文件mybatis-config.xml中添加如下配置
<settings> <!--二级缓存默认开启,false关闭--> <setting name="cacheEnabled" value="true" /> <!--mybatis日志打印到控制台,以便于观察--> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings>
(2)FemaleMapper.xml 配置如下
<mapper namespace="qinfeng.zheng.FemaleMapper"> <select id="getFemaleById" resultType="qinfeng.zheng.entity.Female" parameterType="int"> SELECT id,name FROM tb_female where id = #{id}; </select> <cache eviction="LRU" type="qinfeng.zheng.RedisCache"/> </mapper>
LRU是mybatis默认的过期策略
(3)qinfeng\\zheng\\RedisCache.java
import org.apache.ibatis.cache.Cache; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Map; /** * 使用redis的Hash结构 */ public class RedisCache implements Cache { private String id; private JedisPool jedisPool; private static int EXPIRE_TIME = 1000 * 1000; public RedisCache(String id) { if (id == null) { throw new IllegalArgumentException("Cache instances require an ID"); } this.id = id; JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPool = new JedisPool(jedisPoolConfig, "192.168.79.221", 6379, 3000, "123456"); } @Override public String getId() { return id; } @Override public void putObject(Object key, Object value) { execute(jedis -> { try { ByteArrayOutputStream stream = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(stream); outputStream.writeObject(value); byte[] idBytes = id.getBytes(); jedis.hset(idBytes, key.toString().getBytes(), stream.toByteArray()); // 设置一个过期时间。。 if (jedis.ttl(idBytes) == -1) { jedis.expire(idBytes, EXPIRE_TIME); } } catch (Exception e) { throw new RuntimeException("put object to redis error!", e); } return null; }); } @Override public Object getObject(Object key) { return execute(jedis -> { try { byte[] bytes = jedis.hget(id.getBytes(), key.toString().getBytes()); if (bytes == null) { return null; } ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); return objectInputStream.readObject(); } catch (Exception e) { throw new RuntimeException("get data from redis error!", e); } }); } @Override public Object removeObject(Object key) { return execute(jedis -> jedis.hdel(id.getBytes(), key.toString().getBytes())); } @Override public void clear() { execute(jedis -> jedis.del(id.getBytes())); //因为id是String类型,所以直接jedis.del(id)也行 } @Override public int getSize() { return (Integer) execute(jedis -> { Map<byte[], byte[]> map = jedis.hgetAll(id.getBytes()); return map.size(); }); } private Object execute(RedisCallBack redisCallBack) { try (Jedis jedis = jedisPool.getResource()) { return redisCallBack.callBack(jedis); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } } }
public interface RedisCallBack { Object callBack(Jedis jedis); }
使用redis作为mybatis的二级缓存框架,最主要就是实现mybatis提供的spi接口--Cache即可,然后实现putObject,getObject这两个主要的方法即可。
除此之外,记得pom.xml文件中添加jedis依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
(4)修改测试代码
public class V1Test { public static void main(String[] args) { try (InputStream is = Resources.getResourceAsStream("mybatis-config.xml")) { SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); FemaleMapper femaleMapper = sqlSession.getMapper(FemaleMapper.class); Female female = femaleMapper.getFemaleById(1); System.out.println(female); System.out.println("-----------分隔符----------------------------------"); SqlSession sqlSession2 = sqlSessionFactory.openSession(true); FemaleMapper femaleMapper2 = sqlSession2.getMapper(FemaleMapper.class); Female female2 = femaleMapper2.getFemaleById(1); System.out.println(female2); } catch (Exception e) { e.printStackTrace(); } } }
第一次运行:
Opening JDBC Connection Created connection 331510866. ==> Preparing: SELECT id,name FROM tb_female where id = ?; ==> Parameters: 1(Integer) <== Columns: id, name <== Row: 1, soga <== Total: 1 Female(id=1, name=soga) -----------分隔符---------------------------------- Opening JDBC Connection Created connection 1316061703. ==> Preparing: SELECT id,name FROM tb_female where id = ?; ==> Parameters: 1(Integer) <== Columns: id, name <== Row: 1, soga <== Total: 1 Female(id=1, name=soga)
哈哈,貌似还是查库两次,redis缓存好像没有起到作用。
事实上,mybatis框架为二级缓存提供了一个缓冲Map, 需要在调用commit方法之后,才会将缓冲区Map中的数据写入到redis中。
我们修改一下测试代码,然后再运行观察结果
public class V1Test { public static void main(String[] args) { try (InputStream is = Resources.getResourceAsStream("mybatis-config.xml")) { SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); FemaleMapper femaleMapper = sqlSession.getMapper(FemaleMapper.class); Female female = femaleMapper.getFemaleById(1); System.out.println(female); sqlSession.commit(); System.out.println("-----------分隔符----------------------------------"); SqlSession sqlSession2 = sqlSessionFactory.openSession(true); FemaleMapper femaleMapper2 = sqlSession2.getMapper(FemaleMapper.class); Female female2 = femaleMapper2.getFemaleById(1); System.out.println(female2); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
哎哎哎,报了个错,记得Female 需要序列化
Opening JDBC Connection Created connection 490150701. ==> Preparing: SELECT id,name FROM tb_female where id = ?; ==> Parameters: 1(Integer) <== Columns: id, name <== Row: 1, soga <== Total: 1 Female(id=1, name=soga) -----------分隔符---------------------------------- Cache Hit Ratio [qinfeng.zheng.FemaleMapper]: 0.5 Female(id=1, name=soga)
请看,这次只查了一个库,第2冲直接缓存命中、
我们再运行一次刚才的代码
Cache Hit Ratio [qinfeng.zheng.FemaleMapper]: 1.0 Female(id=1, name=soga) -----------分隔符---------------------------------- Cache Hit Ratio [qinfeng.zheng.FemaleMapper]: 1.0 Female(id=1, name=soga)
两次都缓存命中!!
再看一下redis:
好了, mybatis整合redis为二级缓存到此完毕,下章分析一下它的源码实现!
以上是关于mybatis集成redis作为二级缓存的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 入门:集成Redis哨兵模式,实现Mybatis二级缓存