该篇博客会持续完善与更新,欢迎大神留言指教
原创文章转载请注明来源:https://blog.csdn.net/weixin_41756573/article/details/88719311
一:搭建项目基础架构
1.pom.xml(基于springboot2.0.1)
pom文件中标为蓝色的表示是实现基于redis缓存的相关依赖
<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.0</modelVersion>
<groupId>com.system.redis</groupId>
<artifactId>redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springboot2.0.1 cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- 使用redis作为缓存中间件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 使用Jackson做序列化与反序列化 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.搭建项目的启动类
@SpringBootApplication
@EnableCaching // 开启缓存
@EnableTransactionManagement // 开启事务,保证redis与mysql中数据的一致性
@MapperScan("com.system.redis.mapper") //整合MyBatis,当前案例采用xml的方式配置sql
public class RedisCacheApplication {
// 使用Redis缓存采用Jackson进行序列化与反序列化是实体类不需要实现java.io.Serializable接口
// 不使用springboot默认采用JDK进行序列化的操作,通过以下配置修改为基于Jackson的序列化操作
@Bean
public RedisCacheConfiguration redisCacheConfiguration(){
//加载redis缓存的默认配置
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return configuration;
}
public static void main(String[] args) {
SpringApplication.run(RedisCacheApplication.class, args);
}
}
3.application.properties
#关于redis的设置,此处只提供了redis的简单配置
spring.redis.database=3
spring.redis.host=127.0.0.1
spring.redis.port=6379
#关于对数据库的设置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/boot_emp?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
二:缓存操作
1.步骤
1.在pom.xml中加入关于缓存的依赖spring cache , redis , jackson(上面pom.xml中标为蓝色的部分)
2.在该项目的启动类中开启对缓存的支持,加入@EnableCaching注解
3.在service层中的方法上添加相应的注解
3-1:与insert,update相关的缓存注解 @CachePut
例如:
@CachePut(value="emp", key="#emp.empId")
public Emp insertEmp(Emp emp){
empMapper.insertEmp(emp);
return emp;
}
理解:
1.此时会进行两个操作,一个是将实体类Emp中的属性值写入mysql数据库,另一个是将实体类中的属性值写入redis缓存,我在mysql端采用的是主键自增,将主键返回后作为@CachePut的key,在写入到redis缓存中,如果没有将主键返回,却依然使用主键作为@CachePut的key,即使此处采用了springboot的声明式事务也会导致数据库中有数据而redis缓存中没有数据,声明式事务无法控制这种情况(具体原理还没有搞清楚,欢迎大神留言评论)
2.请注意返回值,将返回值写入到redis缓存(我认为此处的返回值是实体类属性值,对于insert操作请返回主键)
3-2:delete操作采用 @CacheEvict
2.案例:
// delete @CacheEvict 通过 value+key 去删除redis中数据
@CacheEvict(value="emp", key="#empId")
public void deleteByEmpId(Integer empId){
empMapper.deleteByEmpId(empId);
}
三.启用声明式事务,保持数据一致性
1.步骤
1.在启动类中加入@EnableTransactionManagement注解开启事务
2.在service层需要进行事务管理的方法加入@Transactional
2.案例
// insert @CachePut 将返回值写入到Redis中
@Transactional
@CachePut(value="emp", key="#emp.empId")
//@Cacheable(value="emp", key="#emp.empId")
public Emp insertEmp(Emp emp){
empMapper.insertEmp(emp);
/**
* 事务的相关处理,保证数据库与redis的数据的一致性
* 对数据库进行操作后,即将要对redis操作是发生错误,如果发生,需要数据库进行信息回滚
*/
//System.out.println("即将发生错误...");
//System.out.println(10/0); // 发生错误,如何保证数据的一致性
return emp;
}
同时将数据插入mysql数据库和redis缓存
1.@Transactional+@CachePut,无法解决的问题,在往redis缓存中插入数据时redis突然宕机,此时插入数据库中会插入数据,而redis中不会包含缓存
2.@Transactional+@Cacheable就可以解决上面的问题