关于redis的安装、配置及启动,参考Redis简单配置使用
1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.添加配置文件
#Redis数据库索引(默认为0)
spring.redis.database=0
#Redis服务器地址
spring.redis.host=localhost
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=123456
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=1000
3.添加配置类
Redis 不是应用的共享内存,它只是一个内存服务器,就像 MySql ,我们需要将应用连接到它并使用某种“语言”进行交互,因此我们还需要一个连接工厂以及一个 Spring 和 Redis 对话要用的 RedisTemplate,这些都是 Redis 缓存所必需的配置.
Redis 可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。
代码:
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object object:objects) {
sb.append(object.toString());
}
return sb.toString();
}
};
}
// 要启用缓存支持,我们需要创建一个新的 CacheManager bean
@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager manager = new RedisCacheManager(redisTemplate);
return manager;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
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.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
以下内容是针对上面配置的一些解释说明:
1.关于public KeyGenerator keyGenerator():
对于使用 @Cacheable 注解的方法,每个缓存的 key 生成策略默认使用的是参数名+参数值,比如以下方法:
@Cacheable("users")
public User findByUsername(String username)
这个方法的缓存将保存于 key 为 users~keys 的缓存下,对于 username 取值为 "赵德芳" 的缓存,key 为 "username-赵德芳"。一般情况下没啥问题,但是如果方法 key 取值相等然后参数名也一样的时候就出问题了,如:
@Cacheable("users")
public Integer getLoginCountByUsername(String username)
这个方法的缓存也将保存于 key 为 users~keys 的缓存下。对于 username 取值为 "赵德芳" 的缓存,key 也为 "username-赵德芳",将另外一个方法的缓存覆盖掉。
解决办法是使用自定义缓存策略,对于同一业务(同一业务逻辑处理的方法,哪怕是集群/分布式系统),生成的 key 始终一致,对于不同业务则不一致:
于是上述两个方法,对于 username 取值为 "赵德芳" 的缓存,虽然都还是存放在 key 为 users~keys 的缓存下,但由于 key 分别为 "类名-findByUsername-username-赵德芳" 和 "类名-getLoginCountByUsername-username-赵德芳",所以也不会有问题。
这对于集群系统、分布式系统之间共享缓存很重要,真正实现了分布式缓存。
2.RedisTemplate:
spring 封装了 RedisTemplate 对象来进行对redis的各种操作,它支持所有的 redis 原生的 api。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。因此被缓存对象需要实现java.io.Serializable接口,否则缓存出错。(比如后面要用到的User)。
RedisTemplate中定义了对5种数据结构操作
redisTemplate.opsForValue();//操作字符串
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set
模板中的Redis key的类型(通常为String)如:RedisTemplate<String, Object>
注意:如果没特殊情况,切勿定义成RedisTemplate<Object, Object>,否则根据里氏替换原则,使用的时候会造成类型错误 。
3.StringRedisTemplate与RedisTemplate
两者的关系是StringRedisTemplate继承RedisTemplate。
两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
4.定一个User类
//RedisTemplate下被缓存的对象一定要实现Serializable接口
public class User implements Serializable {
private String name;
private int age;
private String email;
public User() {
super();
}
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
'}';
}
}
5.测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate redisTemplate;
@Test
public void contextLoads() {
stringRedisTemplate.opsForValue().set("myKey", "123456");
System.out.println(stringRedisTemplate.opsForValue().get("myKey"));
}
@Test
public void testObj() throws Exception {
User user = new User("archerLj", 27, "lj0011977@163.com");
ValueOperations<String, User> operations = redisTemplate.opsForValue();
operations.set("myUser", user);
operations.set("myUser2", user,1, TimeUnit.MINUTES); //设置缓存过期时间为1分钟。
Thread.sleep(60000);
boolean exists = redisTemplate.hasKey("myUser");
if (exists) {
System.out.println("key myUser exists");
} else {
System.out.println("key myUser not exists");
}
boolean exists2 = redisTemplate.hasKey("myUser2");
if (exists2) {
System.out.println("key myUser2 exists");
} else {
System.out.println("key myUser2 not exists");
}
}
}
----------------------下面是注解方式的使用-----------
1.添加以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
使用mysql数据库,JPA来做数据操作。
2.定义实体类User
package com.example.demo.domain;
@Entity
public class User implements Serializable {
@Id
private int id;
private String name;
private int age;
private String email;
public User() {
super();
}
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
'}';
}
}
3. 在启动类添加实体类扫描目录并开启缓存。
@EnableCaching
@ComponentScan("com.example.demo.domain")
public class DemoApplication {}
4.UserRepository接口定义
@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository<User, Long> {
@Cacheable(key = "#p0")
User findByName(String name);
@CachePut(key = "#p0.name")
User save(User user);
}
5.启动类添加两个请求:
@RestController
@SpringBootApplication
@EnableCaching
@ComponentScan("com.example.demo.domain")
public class DemoApplication {
@Autowired
UserRepository userRepository;
@RequestMapping("/getUser")
public User getUser() {
User user = userRepository.findByName("archerLj");
return user;
}
@RequestMapping("/save")
public User save() {
User user = userRepository.findByName("archerLj");
user.setAge(102);
return userRepository.save(user);
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
6.修改配置
spring.datasource.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
数据库:
use test1;
create table User(
id int primary key auto_increment,
name varchar(20),
age int,
email varchar(30)
) default charset=utf8;
insert into test1.User(name, age, email) values("archerLj", 27, "lj0011977@163.com");
7.测试:
访问http://localhost:8080/getUser
,第一次访问,后台会打印sql语句,第二次访问会直接从缓存中获取,不会再打印sql。
访问http://localhost:8080/save
来修改用户的age
属性,再访问http://localhost:8080/getUser
,发现没有打印sql,但age
属性已经随着修改了。修改的数据之所以能同步到缓存中,是因为@CachePut
注解起的作用。
参考:
如何使用RedisTemplate访问Redis数据结构
springboot(三):Spring boot中Redis的使用
Spring Boot中的缓存支持(二)使用Redis做集中式缓存