配置Mybatis二级缓存为Redis来实现内容缓存
为了使用缓存功能,要大量修改Service实现类,增加处理缓存的业务逻辑。有没有一个更好的办法实现呢,不用每次都修改Service具体实现类?
答案是有,我们分析一下我们的架构体系,我们除了可以在Service层做处理意外,也可以考虑在DAO层做处理,但是DAO层我们只是定义了相关接口,具体的数据增删改查都是动态代理在Mybatis层实现的,我们有没有一个办法能在Mybatis层来处理一下实现缓存功能?
答案是有办法,还记得在第四阶段我们学习Mybatis的时候涉及到一个缓存的概念,当时和大家讲过一级缓存和二级缓存
Mybatis二级缓存原理
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
在同一个namespace下的mapper文件中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则二级缓存清空。
二级缓存是mapper级别的。Mybatis默认是没有开启二级缓存。
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存。
代码实例:
1.导包
2.Mybtais_con.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--开启二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
3.mapper文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ujiuye.mapper.UserDao">
<!--eviction="LRU" redis的内存管理策略-->
<cache eviction="LRU" type="com.ujiuye.util.RedisCache"/>
<select id="getAll" resultType="com.ujiuye.bean.UserInfo" useCache="true">
select *from userinfo
</select>
<update id="update" parameterType="com.ujiuye.bean.UserInfo">
update userinfo set username=#{username},password=#{password} where uid=#{uid}
</update>
<delete id="del">
delete from userinfo where uid=#{0}
</delete>
<insert id="add" parameterType="com.ujiuye.bean.UserInfo">
insert into userinfo values (null ,#{username},#{password},#{birthday})
</insert>
</mapper>
4.自定义缓存
public class RedisCache implements Cache {
private final String id;
private Jedis jedis;
public RedisCache(final String id){
this.id=id;
System.out.println(">>>>>>>>>id==="+id);
ApplicationContext context=new ClassPathXmlApplicationContext("bean_core.xml");
JedisPool jedisPool = context.getBean(JedisPool.class);
jedis=jedisPool.getResource();
}
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object key, Object value) {
jedis.set(key.toString().getBytes(),SerializeUtil.serialize(value));
System.out.println("===putObject==="+key+"====value="+value);
jedis.close();
}
@Override
public Object getObject(Object key) {
byte[] bytes = jedis.get(key.toString().getBytes());
Object value = SerializeUtil.deserialize(bytes);
System.out.println("===getObject==="+key+"====values=="+value);
jedis.close();
return value;
}
@Override
public Object removeObject(Object key) {
//让有效期变成0 ,就自动失效,相当于删除
Object expire = jedis.expire(key.toString().getBytes(), 0);
System.out.println("===removeObject=="+expire);
jedis.close();
return expire;
}
@Override
public void clear() {
//清空
jedis.flushDB();
jedis.close();
}
@Override
public int getSize() {
long size = jedis.dbSize();
return Integer.parseInt(size+"");
}
@Override
public ReadWriteLock getReadWriteLock() {
return new ReentrantReadWriteLock();
}
}
5.测试:
@Test
public void test() throws IOException {
//1.读取全局配置
InputStream is= Resources.getResourceAsStream("mybatis_conf.xml");
SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(is);
SqlSession session=ssf.openSession();
//执行查询
UserDao mapper = session.getMapper(UserDao.class);
List<UserInfo> list = mapper.getAll();
// System.out.println(list);
//执行更新时,缓存自动删除
UserInfo u=new UserInfo();
u.setUsername("admin");
u.setPassword("123");
u.setBirthday("2018-2-10 23:12:2");
mapper.add(u);
session.commit();
//不关闭,不会保存缓存
session.close();
}
第一次 将结果存入缓存中
第二次 不再查询,直接从缓存中读取