1 连接redis
默认有三种方式连接redis.
第一种:jedis---传统的项目--ssm
第二种:lettuce:---->刚出现没有多久就被springboot整合进来。
第三种:springboot连接redi
1.1 jedis操作redis服务器
(1)引入jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
(2)编写相关的代码
@Test
public void test01(){
//Jedis(String host, int port)
Jedis jedis=new Jedis("192.168.40.166",6379);
Set<String> keys = jedis.keys("*");
System.out.println(keys);
//对string数据类型操作
String set = jedis.set("k3", "hello xiaoshi");
System.out.println("set==="+set);
String v3 = jedis.get("k3");
System.out.println("v3===="+v3);
jedis.setex("k4",60,"hello shi");
//对hash数据类型操作
Map<String,String> map=new HashMap<String,String>();
map.put("name","石雨鹏");
map.put("age","14");
map.put("sex","男");
jedis.hset("k5",map);
Map<String, String> map1 = jedis.hgetAll("k5");
System.out.println(map1);
//list队列
jedis.lpush("k6","王永亮","乔文庆","石雨鹏","仝敏");
List<String> k6 = jedis.lrange("k6", 0, -1);
System.out.println(k6);
jedis.close();
}
每次使用jedis对象时 都需要自己创建,当使用完后,需要关闭该对象。===>jedis中也存在连接池.
1.2 jedis连接池的使用
@Test
public void testPool(){
// 连接池的配置信息
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(10); // 最多的连接个数
config.setMaxIdle(10); // 最多空闲的连接个数
config.setMinIdle(2); // 最小空闲的连接个数
config.setTestOnBorrow(true); // 在获取连接对象时是否验证该连接对象的连通性
// 创建连接池
JedisPool jedisPool = new JedisPool(config,"192.168.40.166",6379);
Jedis jedis = jedisPool.getResource();
System.out.println(jedis.keys("*"));
System.out.println(jedis.get("k2"));
System.out.println(jedis.lrange("k6", 0, -1));
jedis.close(); //归还连接池
}
1.3 测试jedis使用和不使用连接池的效率
@Test
public void test03(){
//连接池的配置信息
JedisPoolConfig config=new JedisPoolConfig();
config.setMaxTotal(100);//最多的连接个数
config.setMaxIdle(10); //最多空闲的连接个数
config.setMinIdle(2); //最小的空闲个数
config.setTestOnBorrow(true);//在获取连接对象时是否验证该连接对象的连通性
//创建连接池对象
JedisPool jedisPool=new JedisPool(config,"192.168.40.166",6379);
long start = System.currentTimeMillis();
for(int i=0;i<10000;i++){
Jedis jedis = jedisPool.getResource();
String ping = jedis.ping();
jedis.close();
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
}
@Test
public void test02(){
long start = System.currentTimeMillis();
//Jedis(String host, int port)
for(int i=0;i<10000;i++){
Jedis jedis=new Jedis("192.168.40.166",6379);
String ping = jedis.ping();
jedis.close();
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
}
1.4 springboot整合redis
springboot在整合redis时提高两个模板类,StringRedisTemplate和RedisTemplate.以后对redis的操作都在该模板类中。StringRedisTemplate是RedisTemplate的子类。
<!--redis相关的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
修改配置文件
#redis的配置信息
spring.redis.host=192.168.40.166
spring.redis.port=6379
#最多获取数
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
测试:
@SpringBootTest
class SpringbootRedisApplicationTests {
// 因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理
// StringRedisTemplate会把对每一种数据的操作单独封装成一个类。
@Autowired
private StringRedisTemplate redisTemplate;
/**
* String字符串
*/
@Test
void testString() {
// System.out.println(redisTemplate.keys("*"));
// Boolean hasKey = redisTemplate.hasKey("k1");//判断是否存在指定的key
// System.out.println("判断是否存在指定的key:" + hasKey);
// Boolean k1 = redisTemplate.delete("k1");//删除指定的key
// System.out.println("是否删除指定key成功:" + k1);
ValueOperations<String, String> forString = redisTemplate.opsForValue();
// set key value: 设置指定 key 的值
forString.set("k1","xiaoShi");
// get key 获取指定 key 的值。
System.out.println(forString.get("k1"));
// mset key value key value .... 同时设置一个或多个 key-value 对。
Map map = new HashMap();
map.put("k2","v2");
map.put("k3","3");
forString.multiSet(map);
// mget key key .... 获取所有(一个或多个)给定 key 的值。
List list = new ArrayList();
list.add("k1");
list.add("k2");
List list1 = forString.multiGet(list);
System.out.println(list1);
// incr key 将 key 中储存的数字值增一。 点赞 收藏
System.out.println(forString.increment("k3"));
// decr key 将 key 中储存的数字值减一
System.out.println(forString.decrement("k3"));
// setnx key value 只有在 key 不存在时设置 key 的值。
System.out.println(forString.setIfAbsent("k1", "nihao"));
}
/**
* Hash
*/
@Test
void testHash(){
HashOperations<String, Object, Object> forHash = redisTemplate.opsForHash();
// hset key field value 将哈希表 key 中的字段 field 的值设为 value 。
forHash.put("k1","name","xiaoshi");
forHash.put("k1","age","23");
Map<String,String> map=new HashMap<>();
map.put("name","aaa");
map.put("age","18");
map.put("sex","男");
forHash.putAll("k2",map);
// hget key field 获取存储在哈希表中指定字段的值
System.out.println(forHash.get("k1", "name"));
// hget key 获取在哈希表中指定 key 的所有字段和值
System.out.println(forHash.entries("k1"));
// hkeys key 获取所有哈希表中的字段
System.out.println(forHash.keys("k2"));
// hvals key 获取哈希表中所有值
System.out.println(forHash.values("k2"));
}
/**
* List
*/
@Test
void testList(){
ListOperations<String, String> forList = redisTemplate.opsForList();
// LPush key value value value... 将一个或多个值插入到列表头部
// forList.leftPushAll("k1","shi","shi2","shi3");
// lrange key start end 获取列表指定范围内的元素
System.out.println(forList.range("k1", 0, -1));
// lpop key 移出并获取列表的第一个元素
System.out.println(forList.leftPop("k1"));
}
/**
* Set
*/
@Test
void testSet(){
SetOperations<String, String> forSet = redisTemplate.opsForSet();
// sadd key value value ....向集合添加一个或多个成员
// forSet.add("k1","shi","shi2","shi3","shi");
// forSet.add("k2","shi4","shi2","shi5","shi3");
// smemebers key 返回集合中的所有成员
System.out.println(forSet.members("k1"));
// srandmember key 随机获取一个或多个元素
System.out.println(forSet.randomMember("k2"));
// sinter key key: 返回给定所有集合的交集
System.out.println(forSet.intersect("k1", "k2"));
}
/**
* sort set
*/
@Test
void testSortSet(){
ZSetOperations<String, String> forZSet = redisTemplate.opsForZSet();
// zadd key score value score value :向有序集合添加一个或多个成员,或者更新已存在成员的分数
forZSet.add("k1","shi",100);
forZSet.add("k1","wang",80);
forZSet.add("k1","qiao",90);
// zrange key 通过索引区间返回有序集合成指定区间内的成员
System.out.println(forZSet.range("k1", 0, -1));
// zrevrank key start end 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
System.out.println(forZSet.reverseRange("k1", 0, -1));
}
}
1.4.2 RedisTemplate
它是StringRedisTemplate的父类,它类可以存储任意数据类型,但是任意类型必须序列化,默认采用的是jdk的序列化方式。jdk序列化方式阅读能力差,而且占用空间大. 我们在使用是一般需要人为指定序列化方式。
@SpringBootTest
class SpringbootRedisApplicationTests2 {
@Autowired
private RedisTemplate redisTemplate;
//org.springframework.core.serializer.support.SerializationFailedException
//因为user对象在jvm内存中,---放入redis服务器---持久化到磁盘上。---要该对象的类必须序列化
//key和value都是乱码---因为它默认采用的序列化方式jdk的序列化方式。但是阅读不方便。我们一般不是jdk的序列化方式
@Test
void contextLoads() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set("user",new User(1,"石",23,"男"));
System.out.println(opsForValue.get("user"));
}
}
如果每次使用都人为指定序列化方式,统一设置redisTemplate的序列化
package com.syp;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @program: springboot-redis
* @description:
* @author: 小石
* @create: 2023-04-24 16:25
**/
@Configuration
public class RedisConfig {
//比如验证码
@Bean //该方法的返回对象交于spring容器管理
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);
// field 序列化
template.setHashKeySerializer(redisSerializer);
return template;
}
}
上面的连接都是连接的单机版的redis,真实项目它们的redis都是集群模式.
1.5 springboot连接集群
#最多获取数
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
#设置redis重定向的次数---根据主节点的个数
spring.redis.cluster.max-redirects=3
spring.redis.cluster.nodes=192.168.40.166:7001,192.168.40.166:7002,192.168.40.166:7003,192.168.40.166:7004,192.168.40.166:7005,192.168.40.166:7006
2. redis的应用场景
2.1 redis可以作为缓存
(1) 缓存的原理
(2)缓存的作用:
减少访问数据库的频率。--提高系统的性能。
(3)什么样的数据适合放入缓存
查询频率高的
修改频率低的
数据安全性要求低的。
(4) 如何使用缓存
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.syp</groupId>
<artifactId>springboot-redis02</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-redis02</name>
<description>springboot-redis02</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
(3)配置文件
server.port=8080
spring.datasource.url=jdbc:mysql:///db1
spring.datasource.username=root
spring.datasource.password=shi001104
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#redis的配置信息
spring.redis.host=192.168.40.166
spring.redis.port=6379
#最多获取数
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
(4)servie
package com.syp.service.Impl;
import com.syp.mapper.UserMapper;
import com.syp.pojo.User;
import com.syp.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
/**
* @program: springboot-redis02
* @description:
* @author: 小石
* @create: 2023-04-24 20:30
**/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RedisTemplate redisTemplate;
@Override
public User getById(Integer id) {
ValueOperations forValue = redisTemplate.opsForValue();
Object o = forValue.get("user::" + id); //查询缓存
if (o != null){ //缓存命中
return (User) o;
}
User user = userMapper.selectById(id);
if (user != null){ //查询到应该放入缓存
forValue.set("user::" + id ,user);
}
return user;
}
}