缓存的存在是用来解决数据库访问压力
极少发生修改, 更多用于查询情况
, 比如地址, 省, 市, 等集群 : 将同一种服务的多个节点放在一起共同对系统提供服务的过程称之为集群
分布式 : 有多个不同服务集群
共同对系统提供服务这个系统称之为分布式系统
标签, 打开本地缓存org.apache.ibatis.cache.impl.PerpetualCache
实现public class RedisCache implements Cache {
cache type="com.zy.cache.RedisCache"/>
注意: 这里连接的Redis
和MySQL
服务都在远程服务器上
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.6.RELEASEversion>
parent>
<groupId>com.zygroupId>
<artifactId>redartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.3version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.38version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.19version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
spring:
redis:
host: 192.168.80.131
port: 6379
database: 0
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.80.131/redis_cache?characterEncoding=UTF-8
username: root
password: 1111
mybatis:
mapper-locations: classpath:com/zy/mapper/*.xml
type-aliases-package: com.zy.entity
logging:
level:
com:
zy:
dao: debug
@Data
@Accessors(chain = true)
public class User implements Serializable {
private String id;
private String name;
private Integer age;
private Date bir;
}
// ------------------------
public interface UserDao {
List<User> findAll();
}
// ------------------------
public interface UserService {
List<User> findAll();
}
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Resource
private UserDao userDao;
@Override
public List<User> findAll() {
return userDao.findAll();
}
}
// ------------------------
@SpringBootApplication
@MapperScan("com.zy.dao")
public class RedisCacheApplication {
public static void main(String[] args) {
SpringApplication.run(RedisCacheApplication.class, args);
}
}
<mapper namespace="com.zy.dao.UserDao">
<select id="findAll" resultType="User">
SELECT id, name, age, bir FROM t_user
select>
mapper>
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestUserService {
@Resource
private UserService userService;
@Test
public void test() {
List<User> users = userService.findAll();
users.forEach(user -> System.out.println("user = " + user));
System.out.println("------------------------------------");
userService.findAll().forEach(user -> System.out.println("user = " + user));
}
}
在mybatis没有开启缓存, 每一次查询同样的sql语句, 都是从数据库查的
开启mybatis的二级缓存, 在mapper.xml文件中添加
且实体类要实现序列化
标签即可
<cache/>
mybatis虽然提供了这种缓存的方式, 但是这种方式只局限于当前的程序,当程序停止运行(JVM关闭)缓存就没了, 当再次启动程序后, 还是会去数据库中查询, 这种缓存属于本地缓存
MyBatis的缓存默认是实现public class PerpetualCache implements Cache
来实现的, 底层使用的是一个HashMap;
<mapper namespace="com.zy.dao.UserDao">
<cache type="com.zy.cache.RedisCache"/>
<select id="findAll" resultType="User">
SELECT id, name, age, bir FROM t_user
select>
mapper>
因为RedisCache
的实例化是由mybatis来操作的, 并不是Spring容器, 所以不能直接注入RedisTemplate; 此时的问题是如何拿到RedisTemplate
, 往putObject / getObject方法中 放/取 值呢?
/**
* Description: 用来获取SpringBoot创建好的工厂
*
* @author zygui
* @date Created on 2020/7/27 17:12
*/
@Configuration
public class ApplicationContextUtils implements ApplicationContextAware {
// 此时就是内部创建好的工厂
private static ApplicationContext applicationContext;
// 将创建好的工厂以参数的形式传递给这个类
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
// 提供在工厂中获取对象的方法
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
}
/**
* Description: 自定义Redis缓存实现
*
* @author zygui
* @date Created on 2020/7/27 16:55
*/
public class RedisCache implements Cache {
private final String id;
// 必须存在构造方法
public RedisCache(String id) {
// id 就是当前放入缓存的mapper的namespace ---> com.zy.dao.UserDao
System.out.println("id =============> " + id);
this.id = id;
}
// 返回cache的唯一标识
@Override
public String getId() {
return this.id;
}
// 往缓存中放值 --> 使用 RedisTemplate往缓存中放值
// key ---> -983043073:3242099914:com.zy.dao.UserDao.findAll:0:2147483647:SELECT id, name, age, bir FROM t_user:SqlSessionFactoryBean
@Override
public void putObject(Object key, Object value) {
System.out.println("key = " + key);
// 通过ApplicationContextUtils来获取redisTemplate
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// 使用hash类型作为缓存存储模型 > ==> >
redisTemplate.opsForHash().put(id, key.toString(), value);
}
// 往缓存中取值, 这个key
// key ---> -983043073:3242099914:com.zy.dao.UserDao.findAll:0:2147483647:SELECT id, name, age, bir FROM t_user:SqlSessionFactoryBean
@Override
public Object getObject(Object key) {
System.out.println("key = " + key);
// 通过ApplicationContextUtils来获取redisTemplate
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// 根据key从redis的hash类型中key获取数据
return redisTemplate.opsForHash().get(id, key.toString());
}
@Override
public Object removeObject(Object o) {
return null;
}
@Override
public void clear() {
}
@Override
public int getSize() {
return 0;
}
}
此时运行程序就会发现, 第一次用来查询数据库, 然后将查询的语句存到Redis中, 第二次就从Redis中获取了;
此时当程序结束, 再次启动程序后, 两次查询都会丛Redis中获取了;
我们再测试一个查询, 根据指定id来查询, 一条信息
当执行增删改
会执行RedisCache的clear
方法, 清楚Redis中的缓存
// 当执行增删改会调用这个方法
@Override
public void clear() {
System.out.println("清空缓存");
}
所以我们要对这个方法进行清空redis中的缓存, 否则, 执行完删除操作后, 数据库中的数据被删除了, 但是之前查询的操作还在redis中; 仍然可以查询出来
RedisCache类
/**
* Description: 自定义Redis缓存实现
*
* @author zygui
* @date Created on 2020/7/27 16:55
*/
public class RedisCache implements Cache {
private final String id;
// 必须存在构造方法
public RedisCache(String id) {
// id 就是当前放入缓存的mapper的namespace ---> com.zy.dao.UserDao
System.out.println("id =============> " + id);
this.id = id;
}
// 返回cache的唯一标识
@Override
public String getId() {
return this.id;
}
// 往缓存中放值 --> 使用 RedisTemplate往缓存中放值
// key ---> -983043073:3242099914:com.zy.dao.UserDao.findAll:0:2147483647:SELECT id, name, age, bir FROM t_user:SqlSessionFactoryBean
@Override
public void putObject(Object key, Object value) {
// 使用hash类型作为缓存存储模型 > ==> >
getRedisTemplate().opsForHash().put(id, key.toString(), value);
}
// 往缓存中取值, 这个key
// key ---> -983043073:3242099914:com.zy.dao.UserDao.findAll:0:2147483647:SELECT id, name, age, bir FROM t_user:SqlSessionFactoryBean
@Override
public Object getObject(Object key) {
System.out.println("key = " + key);
// 根据key从redis的hash类型中key获取数据
return getRedisTemplate().opsForHash().get(id, key.toString());
}
// 为mybatis的保留方法, 默认没有实现
@Override
public Object removeObject(Object o) {
System.out.println("根据指定key删除缓存");
return null;
}
// 当执行增删改会调用这个方法
@Override
public void clear() {
System.out.println("清空缓存");
getRedisTemplate().delete(id); // 清空缓存
}
// 用来计算缓存数量
@Override
public int getSize() {
// 获取hash中key value的数量
return getRedisTemplate().opsForHash().size(id).intValue();
}
//封装redisTemplate
private RedisTemplate getRedisTemplate(){
//通过application工具类获取redisTemplate
RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}