**
springboot缓存
**
**
基本环境的搭建
**
1创建springboot项目,并添加相应的依赖
2.配置yml文件
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
#redis
redis:
host: localhost
port: 6379
password: 123456
#配置mybatis
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml # mapper文件
type-aliases-package: com.swj.domain # 别名
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #输出sql语句
3.编写实体类+编写mapper接口
public class tbUser{
private int id;
private String name;
private String pwd;
private int teaId;
//get,set省略(或者可以添加lombok)
}
@Mapper //表示这是mybatis的mapper类
@Repository //表示这是dao层
public interface UserMapper {
//根据id查询用户
tbUser getUserById(int id);
int addUser(tbUser user);
int updateUser(tbUser user);
int deleteUser(int id);
}
4.编写mapper的配置文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.swj.mapper.UserMapper">
<select id="getUserById" parameterType="int" resultType="tbuser">
select * from mybatis.tbuser where id= #{id}
</select>
<insert id="addUser" parameterType="tbuser">
insert into mybatis.tbuser (name,pwd,teaId) values (#{name},#{pwd},#{teaId})
</insert>
<update id="updateUser" parameterType="tbuser">
update mybatis.tbuser set name = #{name} where id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from mybatis.tbuser where id = #{id}
</delete>
</mapper>
mapper配置文件所在路径
5.编写service层
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public tbUser getUserById(int id) {
System.out.println("查询了" + id + "号用户");
return userMapper.getUserById(id);
}
public int addUser(tbUser user) {
return userMapper.addUser(user);
}
public int updateUser(tbUser user) {
return userMapper.updateUser(user);
}
public int deleteUser(int id) {
return userMapper.deleteUser(id);
}
}
6.编写controller层
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getUserById/{id}")
public tbUser getUserById(@PathVariable("id") int id) {
return userService.getUserById(id);
}
@RequestMapping("/addUser")
public String addUser() {
tbUser tbUser = new tbUser(31,"阿毛","234",1);
userService.addUser(tbUser);
return "ok";
}
@RequestMapping("/updateUser")
public String updateUser() {
tbUser tbUser = new tbUser(20,"阿刘","456",1);
userService.updateUser(tbUser);
return "ok";
}
@RequestMapping("/deleteUser/{id}")
public String deleteUser(@PathVariable("id") int id) {
userService.deleteUser(id);
return "ok";
}
}
7.环境搭建成功,启动项目,测试没有问题即可!
**
添加缓存配置
**
1.在启动类用注解(@EnableCaching)开启缓存
@SpringBootApplication
@EnableCaching //开启基于注解的缓存
public class SpringbootCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootCacheApplication.class, args);
}
}
2.在service层中添加注解
@Service
@CacheConfig(cacheNames = "user") //抽取缓存的公共位置
public class UserService {
@Autowired
private UserMapper userMapper;
//将方法的运行结果进入缓存,这样以后再相同的数据直接从缓存中取,不用再调用方法(减少了数据库的交互,提高了效率)
//属性介绍:
// cacheNames/value:缓存组件的名称:用来存放该方法返回值的地方,用数组的方式来存储,可以指定多个缓存
//key:缓存数据用来指定的key,默认key使用方法的参数,或者使用keyGenerator(这个使用在config类中配置),就是key生成器,二选一即可
//CacheManager:指定从哪个缓存管理器取 或者CacheResolver缓存解析器,两者功能一样
//Condition:指定符合条件下,才会进行缓存,condition="#id">0 的情况下才会缓存
//unless:否定缓存,当unless指定的条件时true是就不缓存,可以回去结果进行判断 #result==null;
//sync:是否使用异步模式
@Cacheable(key = "#root.methodName+'['+#id+']'")
public tbUser getUserById(int id) {
System.out.println("查询了" + id + "号用户");
return userMapper.getUserById(id);
}
public int addUser(tbUser user) {
return userMapper.addUser(user);
}
/**
* @CachePut 该注解表示及调用方法, 又更新数据库缓存 同步更新缓存
* 修改某个数据更新缓存
* 运行时机:
* 先调用目标方法,然后把方法的结果缓存起来
* key 要和查询的key保持一致
*/
@CachePut(key = "#root.methodName+'['+#id+']'")
public int updateUser(tbUser user) {
return userMapper.updateUser(user);
}
/***
*@CacheEvict 清除缓存
* allEntries = true 清除所有缓存
* beforeInvocation 是否在方法之前执行,默认是false
*/
@CacheEvict(key = "#root.methodName+'['+#id+']'")
public int deleteUser(int id) {
return userMapper.deleteUser(id);
}
}
3.启动项目测试,以查找为例
3.1在url地址栏上输入:http://localhost:8080/getUserById/2测试
测试完后,查看控制台的输出信息
控制台上输出了service方法中的语句,证明调用了service方法,数据是从数据库中取出的,
3.2先把控制台上的信息清空,在url地址栏可以重复多刷新几遍,但是控制台上并没有任何信息,证明我们的数据没有调用数据库,是从缓存中取出的
springboot整合redis缓存(基于springboot缓存的例子继续整合redis)
1.安装redis数据库跟redis的可视化工具
2.安装成功以后,可以去http://www.redis.cn/commands.html这个网站上查看关于redis一些操作的命令
3.去springboot官网上找redis的启动器:https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/using-spring-boot.html#using-boot-starter
pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
4.配置yml
继续编写yml配置文件了
```yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
redis:
host: 127.0.0.1
#配置mybatis
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml # mapper文件
type-aliases-package: com.swj.domain # 别名
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #输出sql语句
5.在test里进行简单的测试,看看基本的redis环境是否搭建成功(这里测试用的stringRedisTemplate来进行测试)
@SpringBootTest
class SpringbootCacheApplicationTests {
@Autowired
RedisTemplate redisTemplate;//专门操作key-value都是对象的
@Autowired
StringRedisTemplate stringRedisTemplate;//专门操作key-value都是字符串的
/**
* redis常见操作的5大类型
* 1. stringRedisTemplate.opsForValue(字符串);
* 2. stringRedisTemplate.opsForList(list列表);
* 3. stringRedisTemplate.opsForSet(set集合);
* 4.stringRedisTemplate.opsForHash(hash散列);
* 5.stringRedisTemplate.opsZst(Zst有序集合);
*/
@Test
//测试保存字符串
void test() {
stringRedisTemplate.opsForValue().append("hello", "swj!");
}
}
6.stringRedisTemplate测试成功以后,我们在继续测redisTemplate
6.1 添加一个test方法测试redisTemplate
@Autowired
UserMapper userMapper;
@Test //测试保存对象
void test1() throws JsonProcessingException {
tbUser user = userMapper.getUserById(1);
//默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
redisTemplate.opsForValue().set("user", user);
}
启动项目,查看测试是否成功,项目启动后,发现报错了,报错原因是因为序列化
6.2将实体类序列化
什么是java的序列化呢?
序列化:将 Java 对象转换成字节流的过程。
反序列化:将字节流转换成 Java 对象的过程。
当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。
序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。
注意事项:
1.某个类可以被序列化,则其子类也可以被序列化
2.声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述3.类级别的属性,transient 表示临时数据
4.反序列化读取序列化对象的顺序要保持一致
public class tbUser implements Serializable {
private int id;
private String name;
private String pwd;
private int teaId;
}
序列化完以后,我们在继续启动项目,查看是否成功
数据已经存在了redis中,但是却不是我们能够看懂的数据,所以我们选择第二种,让数据变成我们能够看懂的json格式
6.3配置redisConfig类
方式一
@Configuration
public class MyRedisConfig {
@Bean
public RedisTemplate<Object, Object> jsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
//解决日期序列化问题
ObjectMapper om = new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om);
template.setDefaultSerializer(genericJackson2JsonRedisSerializer);
return template;
}
}
方式二
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
配置类完成以后,我们去test里用我们刚刚编写的jsonRedisTemplate继续测试,
@SpringBootTest
class SpringbootCacheApplicationTests {
@Autowired
RedisTemplate redisTemplate;//专门操作key-value都是对象的
@Autowired
StringRedisTemplate stringRedisTemplate;//专门操作key-value都是字符串的
@Autowired
UserMapper userMapper;
@Autowired
RedisTemplate jsonRedisTemplate;// 定义jsonRedisTemplate
@Test
//测试保存字符串
void test() {
stringRedisTemplate.opsForValue().append("hello", "swj!");
}
@Test //测试保存对象
void test1() throws JsonProcessingException {
tbUser user = userMapper.getUserById(1);
//默认如果保存对象,使用jdk序列化机制,序列化后的数据保存到redis中
jsonRedisTemplate.opsForValue().set("user", user);
}
@Test
void contextLoads() {
}
}
启动项目,其数据库中查看结果
7. 启动项目测试,以查找为例
7.1在url地址栏上输入:http://localhost:8080/getUserById/2测试,
报错原因大概是不能够反序列化
7.2编写RedisCacheManager方法,自定义一些缓存规则
@Configuration
public class MyRedisConfig {
@Bean
public RedisTemplate<Object, Object> jsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
//解决日期序列化问题
ObjectMapper om = new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om);
template.setDefaultSerializer(genericJackson2JsonRedisSerializer);
return template;
}
@Bean
//自定义一些缓存规则
public RedisCacheManager jsonRedisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1)) // 设置缓存过期时间为一天
.disableCachingNullValues() // 禁用缓存空值,不缓存null校验
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new
GenericJackson2JsonRedisSerializer())); // 设置CacheManager的值序列化方式为json序列化,可加入@Class属性
return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(cacheConfiguration).build(); // 设置默认的cache组件
}
}
7.3在进行测试,并查看网页上的结果,
http://localhost:8080/getUserById/11
8.如果在编码中想对缓存进行操作
@Service
@CacheConfig(cacheNames = "user") //抽取缓存的公共位置
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private MyRedisConfig myRedisConfig;
@Autowired
RedisConnectionFactory redisConnectionFactory;
@Cacheable(key = "#root.methodName+'['+#id+']'")
public tbUser getUserById(int id) {
System.out.println("查询了" + id + "号用户");
Cache user = myRedisConfig.jsonRedisCacheManager(redisConnectionFactory).getCache("user::getUserById[11]").;
System.out.println("################"+user); //获取了缓存以后,可以对缓存进行操作
return userMapper.getUserById(id);
}
}