一、Mybatis的缓存
- 同大多数ORM层框架一样,Mybatis自然也提供了对一级缓存和二级缓存的支持。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写 到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存 也就不存在了。Mybatis默认开启一级缓存。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同 namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二 次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。
二、redis管理Mybatis二级缓存的实现(Spring Boot项目)
1.引入依赖
<!--引入jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- 引入一个工具包 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
2.在application.yml中编写配置
server:
port: 8081
spring:
session:
store-type: redis # 指定使用redis存储session的会话信息
redis: # 指定redis服务器的相关信息
host: 192.168.174.128
port: 6379
3.实现mybatis的Cache接口,完成自定义缓存
package com.baizhi.cache;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
import redis.clients.jedis.Jedis;
import java.io.Serializable;
import java.util.concurrent.locks.ReadWriteLock;
public class RedisCache implements Cache {
private final String id;
private Jedis cache = new Jedis("192.168.174.128",6379);
public RedisCache(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
//返回缓存所有键值对的数量
public int getSize() {
Long dbSize = cache.dbSize();
return dbSize.intValue();
}
@Override
//向缓存中存入数据
public void putObject(Object key, Object value) {
System.out.println("key:"+key);
//将对象序列化成字节数组 引入commens-lang3工具包
byte[] keyBs = SerializationUtils.serialize((Serializable) key);
byte[] valueBs = SerializationUtils.serialize((Serializable) value);
cache.set(keyBs, valueBs);
}
@Override
//从缓存中获取数据
public Object getObject(Object key) {
byte[] keyBs = SerializationUtils.serialize((Serializable) key);
byte[] valueBs = cache.get(keyBs);
if (valueBs != null) { // 第一次到缓存找数据的时候 , 返回的是null
return SerializationUtils.deserialize(valueBs);
}
return null;
}
@Override
//清除缓存
public Object removeObject(Object key) {
// 先获取一下删除的对象
byte[] keyBs = SerializationUtils.serialize((Serializable) key);
byte[] valueBs = cache.get(keyBs);
Object obj = SerializationUtils.deserialize(valueBs);
cache.del(keyBs);// 执行删除操作
return obj;
}
@Override
//清空缓存
public void clear() {
cache.flushDB();
}
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
@Override
public boolean equals(Object o) {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
if (this == o) {
return true;
}
if (!(o instanceof Cache)) {
return false;
}
Cache otherCache = (Cache) o;
return getId().equals(otherCache.getId());
}
@Override
public int hashCode() {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
return getId().hashCode();
}
}
可以在idea中ctrl+t将PrepetualCache类中的方法粘过来修改一下
4.在mybatis中使用自定义缓存
<!--使用自定义二级缓存-->
<cache type="com.xxxx.cache.RedisCache"></cache>
5.在springboot项目中开启mybatis的二级缓存
mybatis:
mapper-locations: classpath:com/xxxx/mapper/*Mapper.xml
type-aliases-package: com.xxxx.entity
configuration: # 开启mybatis的二级缓存
cache-enabled: true
6.编写好dao service controller层之后,开启测试
- controller
package com.baizhi.controller;
import com.baizhi.entity.User;
import com.baizhi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
import java.util.List;
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("findAll")
public List<User> findAll(){
List<User> users = userService.findAll();
return users;
}
}
- 浏览器输入localhost:8081/user/findAll , 出现如下结果
- pushObject方法中获得的key:
key:514810625:3350643160:com.xxxx.dao.UserDAO.findAll:0:2147483647:select * from t_user:SqlSessionFactoryBean
- redis库中已经存入缓存:
访问一次之后,再次访问就会从缓存中获取数据,就会变得很快,数据量大的时候就比较明显了。
注意:实体类一定要实现Serializable接口