目录:
(1)Jedis连接Redis
(2)Jedis连接池连接Redis
(3)封装JedisUtil对外提供连接对象获取的方法
(4)Jedis操作String数据类型
(5)Jedis操作hash数据类型
(6)Jedis操作list类型的数据
(7)Jedis操作set类型数据
(8)Jedis操作sortesSet数据类型
(9)层级目录、失效时间
(10)获取所有key+事务
(11)Jedis操作byte数组
(12)Redis持久化方案-bgsave
(13)Redis持久化方案-rdb
(1)Jedis连接Redis
通过Java代码操作Redis,通过客户端使用命令比较少
创建springbooot项目,选择依赖:
redis依赖默认继承的是Lettuce客户端,我们先学习Jedis客户端
区别:
Jedis是直连连接的,直接连接到Redis服务器,在多个线程上是共享一个Jedis实例的,所以这个时候线程是不安全的,所以你想在多线程场景下使用Jedis需要使用连接池,每个线程都会使用自己的Jedis实例, 当你的连接数增多的时候呢,会消耗比较多的物理资源 Jedis并发不安全
Lettuce:完全克服线程不安全的特点是基于Netty的连接方式,他支持同步异步响应式的操作,多线程之间呢共享连接实例,不必担心多线程的并发问题,并发比较安全一点
我们需要移出默认的Lettuce依赖,重新引入Redis依赖
pom.xml:
<?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.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xxxx</groupId>
<artifactId>redis-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--
1.x 的版本蓦然采用的连接池技术是Jedis
2.0以上的版本默认采用的连接池是Lettuce
如果采用Jedis,需要排除Lettuce依赖
-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--Jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--web组件依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--test依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yml:配置文件
spring:
redis:
# Redis服务器地址
host: 192.168.67.128
# Redis服务端口
port: 6379
# 设置redis服务器密码
password: root
# 选择那个库,默认是0
database: 0
# 连接超时时间
timeout: 10000ms
jedis:
pool:
# 最大连接数,默认18
max-active: 1024
# 最大连接阻塞时间,单位为毫秒,默认-1ms
max-wait: 10000ms
# 最大空闲连接,默认8
max-idle: 200
# 最小空闲连接
min-idle: 5
测试类:
package com.xxxx.redisdemo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
@SpringBootTest
class RedisDemoApplicationTests {
@Test
public void initConnt(){
//创建Jedis对象,连接redis服务器
Jedis jedis=new Jedis("192.168.67.128",6379);
//设置认证密码
jedis.auth("root");
//指定数据库
jedis.select(1);
//使用pink命令连接是否成功
String result = jedis.ping();
System.out.println(result);
//添加一条数据
jedis.set("name","zhangsan");
//获取数据
String name = jedis.get("name");
System.out.println(name);
//操作完之后关闭jedis
if (jedis!=null){
jedis.close();
}
}
}
redis可视化工具:
(2)Jedis连接池连接Redis
Jedis连接Redis服务器没有问题了,但是我们现在是直接创建的Jedis对象,Jedis是线程不安全的,多线程的情况下我们会用连接池,来处理Jedis,下面我们用连接池来获取我们的一个连接对象 并且操作redis服务器
测试类:
package com.xxxx.redisdemo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@SpringBootTest
class RedisDemoApplicationTests {
//使用Jedis连接池操作Jedis
@Test
public void initConnt2(){
//初始化创建Jedis连接池
JedisPool jedisPool=new JedisPool(new JedisPoolConfig(),"192.168.67.128",6379,10000,"root");
//从连接池获取Jedis对象
Jedis jedis = jedisPool.getResource();
//使用pink命令连接是否成功
String result = jedis.ping();
System.out.println(result);
//指定数据库,默认为0
jedis.select(2);
//添加一条数据
jedis.set("name","wangwu");
//获取数据
String name = jedis.get("name");
System.out.println(name);
//释放资源
if (jedis!=null){
jedis.close();
}
}
}
Jedis客户端可视化工具:
(3)封装JedisUtil对外提供连接对象获取的方法
上面的操作,我们都要新建一个连接池,再获取Jedis对象,再进行相关操作,操作完之后再释放资源,这种逻辑在实际开发中是不允许的,在实际开发中是这样的,当项目启动后,线程池只会创建一次,不可能会被频繁的创建,创建完一次之后呢 ,Jedis从线程池里面拿对象,拿完对象进行操作,操作完之后进行释放资源,下次之后呢直接从线程池去拿就行了,不需要新建一个线程池了,线程值只要新建一次
我们现在新建一个配置类,让线程对象呢只会新建一次
ReidsConfig:
package com.xxxx.redisdemo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class RedisConfig {
//使用Value注解读取注入配置文件内容
//服务器地址
@Value("${spring.redis.host}")
private String host;
//服务器端口
@Value("${spring.redis.port}")
private int port;
//访问密码
@Value("${spring.redis.password}")
private String password;
//连接超时时间
@Value("${spring.redis.timeout}")
private String timeout;
//最大连接数
@Value("${spring.redis.jedis.pool.max-active}")
private int maxTotal;
//最大连接等待阻塞时间
@Value("${spring.redis.jedis.pool.max-wait}")
private String maxWaitMillis;
//最大空闲连接
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
//最小空闲连接
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Bean
public JedisPool getJedisPool(){
//配置
JedisPoolConfig jedisPoolConfig= new JedisPoolConfig();
//最大连接数
jedisPoolConfig.setMaxTotal(maxTotal);
//最大阻塞时间
jedisPoolConfig.setMaxWaitMillis(Long.valueOf(maxWaitMillis.substring(0,maxWaitMillis.length()-2)));
//最大空闲连接
jedisPoolConfig.setMaxIdle(maxIdle);
//最小空闲连接
jedisPoolConfig.setMinIdle(minIdle);
//Jedis对象
JedisPool jedisPool=new JedisPool(jedisPoolConfig,host,port,Integer.valueOf(timeout.substring(0,timeout.length()-2)),password);
return jedisPool;
}
}
测试类:
使用了Junit的注解@Before @After,需要在配置类上面加一个注解@RunWith(SpringRunner.class)注解,否则获取的连接池对象为null
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@Before //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//释放资源
@After
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
这样通过@Autoeired拿到jedisPool,然后在内次运行@test方法之前呢,都会经过@Before从连接池拿到redis对象,结束test方法之后呢,经过@After释放jedis对象
(4)Jedis操作String数据类型
测试类:
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//操作string类型数据
@Test
public void testString(){
//添加数据
jedis.set("name","zhangsan1");
//获取一条数据
String name = jedis.get("name");
System.out.println(name);
//添加多条数据
jedis.mset("address","sh","sex","1");
//获取多条数据
List<String> list = jedis.mget("name", "address", "sex");
list.forEach(System.out::println);
//删除数据
Long result = jedis.del("name");
System.out.println(result);
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
运行@Test
出现了异常:解决办法
有关使用junit依赖出现@Before或者@Before注解不生效
有可能是Junit使用版本过高,有两种解决方法:
1.如果Junit使用版本较高,可以使用@BeforeEach和@AfterEach代替@Before和@After
2.降低Junit版本
可视化界面客户端:
看到成功的添加到第一个数据库中:因为name删除了没有添加进来
(5)Jedis操作hash数据类型
测试类:
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//操作hash
@Test
public void testHash(){
//添加一条数据 第一个参数是redis的key 第二个参数hash的key 第三个参数的hash的value
jedis.hset("user","name","zhangsan");
//获取一条数据
String name = jedis.hget("user", "name");
System.out.println(name);
//添加多条数据
Map<String, String> map = new HashMap<>();
map.put("age","20");
map.put("sex","1");
jedis.hmset("user",map);
//获取多条数据
List<String> list = jedis.hmget("user", "age", "sex");
list.forEach(System.out::println);
//获取hash类型的所有数据
Map<String, String> user = jedis.hgetAll("user");
user.entrySet().forEach(e->{
System.out.println(e.getKey()+"-----"+e.getValue());
});
//删除数据
jedis.hdel("user","name","age");
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
可视化客户端:添加了user的hash类型
(6)Jedis操作list类型的数据
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//操作list类型的数据
@Test
public void testlist(){
//左添加
jedis.lpush("students","zhangsan","lisi");
//右添加
jedis.rpush("students","wangwu","zhangliu");
//获取数据 第一个参数redis的key 第二个参数起始下标 第三个参数结束下标
List<String> list = jedis.lrange("students", 0, 3);
list.forEach(System.out::println);
//获取总条数
Long totall = jedis.llen("students");
System.out.println(totall);
//删除数据 第二个参数删除的个数 第三个参数需要删除的值
jedis.lrem("students",1,"lisi");
/*
//左弹出 相当于从左边开始删除一条数据
String left = jedis.lpop("students");
System.out.println(left);
//右弹出 相当于从右边开始删除一条数据
String right = jedis.rpop("students");
System.out.println(right);
*/
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
可视化客户端:
左弹出、右弹出
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//操作list类型的数据
@Test
public void testlist(){
/*//左添加
jedis.lpush("students","zhangsan","lisi");
//右添加
jedis.rpush("students","wangwu","zhangliu");
//获取数据 第一个参数redis的key 第二个参数起始下标 第三个参数结束下标
List<String> list = jedis.lrange("students", 0, 3);
list.forEach(System.out::println);
//获取总条数
Long totall = jedis.llen("students");
System.out.println(totall);
//删除数据 第二个参数删除的个数 第三个参数需要删除的值
jedis.lrem("students",1,"lisi");*/
//左弹出 相当于从左边开始删除一条数据
String left = jedis.lpop("students");
System.out.println(left);
//右弹出 相当于从右边开始删除一条数据
String right = jedis.rpop("students");
System.out.println(right);
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
(7)Jedis操作set类型数据
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//操作set类型的数据
@Test
public void testSet(){
//添加数据
jedis.sadd("letters","aaa","bbb","ccc","ddd","eee");
//获取数据
Set<String> set = jedis.smembers("letters");
set.forEach(System.out::println);
//获取总条数
Long totall = jedis.scard("letters");
System.out.println(totall);
//删除数据
jedis.srem("letters","aaa","bbb");
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
可视化客户端
可视化客户端
(8)Jedis操作sortesSet数据类型
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//操作sorted set
@Test
public void testSortedSet(){
//存储数据
Map<String,Double> map=new HashMap<>();
map.put("zhangsan",7D);
map.put("lisi",3D);
map.put("wangwu",5D);
map.put("zhaoliu",6D);
map.put("tianqi",1D);
jedis.zadd("score",map);
//获取数据 第一个参数redis中的key 第二个参数:起始下标 第三个参数:结束下标
Set<String> set = jedis.zrange("score", 0, 4);
set.forEach(System.out::println);
//获取总条数
Long total = jedis.zcard("score");
System.out.println(total);
//删除数据
jedis.zrem("score","zhagnsan","wangwu");
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
(9)层级目录、失效时间
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.params.SetParams;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//层级目录形式存储数据:
@Test
public void testDir(){
jedis.set("cart:user01:item01","apple");
System.out.println(jedis.get("cart:user01:item01"));
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.params.SetParams;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//key的失效时间
@Test
public void testExpire(){
/*//设置存在的值失效时间30秒
jedis.set("code","test");
//设置失效时间单位 秒
jedis.expire("code",30);
//设置失效时间单位 毫秒
jedis.pexpire("code",30000);
//查看失效时间单位秒 -1:用不失效 -2:已经失效
Long ttl = jedis.ttl("code");
System.out.println(ttl);*/
//添加key设置失效时间
//设置失效时间单位 秒
jedis.setex("code",30,"test");
//设置失效时间单位 毫秒
//jedis.psetex("code",30000,"test");
//查看失效时间单位 毫秒
Long pttl = jedis.pttl("cose");
System.out.println(pttl);
//nx xx用法
SetParams setParams=new SetParams();
//不存在时才能设置成功
setParams.nx();
//存在时才能设置成功
setParams.xx();
//设置失效时间单位 秒
setParams.ex(30);
//设置失效时间单位 毫秒
//setParams.px(30000);
jedis.set("cose","test",setParams);
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
(10)获取所有key+事务
package com.xxxx.redisdemo;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.params.SetParams;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//获取所有key
@Test
public void testAllKey(){
//当前数据库key的数量
Long size = jedis.dbSize();
System.out.println(size);
//查询当前数据库的所有key
Set<String> set = jedis.keys("*");
set.forEach(System.out::println);
}
//事务
@Test
public void testMutil(){
//开启事务
Transaction tx=jedis.multi();
tx.set("tel","10086");
//提交事务
tx.exec();
//回滚事务
//tx.discard();
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
第一个test:
数据库中有7个key
第二个test:
如果注释提交,开启回滚,不会存入数据库
事务比如说操作3张表,第一 第二 已经操作成功了,不会回滚了,第三张表出了问题,它自己回滚,第四章不会运行了
Redis并没有表的概念,它都是key value形式的数据库,没有表的概念,所以正常也没有多表联查的功能,只是说你开启事务混滚功能,它只会把当前出错的数据进行回滚,但是之前操作成功的并不会回滚,事务能力比较弱的
(11)Jedis操作byte数组
非关系型数据库,可以存放一个对象,可以先把这个对相关转换成一个byte数组,把它存到redis里面去
序列化工具类:
SerializeUtil:
package com.xxxx.redisdemo.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializeUtil {
//将java对象转换为byte数组 序列化过程
public static byte[] serialize(Object object){
ObjectOutputStream oos=null;
ByteArrayOutputStream baos=null;
try{
//序列化
baos=new ByteArrayOutputStream();
oos=new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes=baos.toByteArray();
return bytes;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
//将byte数组转换为java对象 反序列化
public static Object unserialize(byte[] bytes){
if (bytes==null) return null;
ByteArrayInputStream bais=null;
try{
//反序列化
bais=new ByteArrayInputStream(bytes);
ObjectInputStream ois=new ObjectInputStream(bais);
return ois.readObject();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
pojo类:User
package com.xxxx.redisdemo.pojo;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID=914893743109191022L;
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
测试类:
package com.xxxx.redisdemo;
import com.xxxx.redisdemo.pojo.User;
import com.xxxx.redisdemo.util.SerializeUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.params.SetParams;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SpringBootTest
@RunWith(SpringRunner.class)
class RedisDemoApplicationTests {
//注入线程池对象
@Autowired
private JedisPool jedisPool;
Jedis jedis=null;
//初始化jedis实例对象
@BeforeEach //每次运行Test之前获取jedisPool对象
public void initConnt3(){
jedis = jedisPool.getResource();
}
//操作byte数组
@Test
public void testByte(){
User user=new User();
user.setId(2);
user.setUsername("zhangsan");
user.setPassword("123456");
//序列化key
byte[] userKey = SerializeUtil.serialize("user:" + user.getId());
//序列化对象
byte[] userValue = SerializeUtil.serialize(user);
//存入Redis
jedis.set(userKey,userValue);
//取出数据
byte[] bytes = jedis.get(userKey);
//反序列化
User user1 =(User) SerializeUtil.unserialize(bytes);
System.out.println(user1);
}
//释放资源
@AfterEach
public void closeConnt(){
if (null!=jedis){
jedis.close();
}
}
}
通过序列化成byte数组存入Redis,通过可视化客户端查看存入的数据,是二进制的看不懂
后面将SpringDataRedis用Lettuce的一个客户端去连接我们的Redis的时候我们会讲一个正常的序列化工具,Redis序列化的配置,去解决二进制的问题
(12)Redis持久化方案-bgsave
Redis是一个在内存中的存储系统,内存有一个优点,就是内存操作数据,比磁盘上操作数据的速度快,效率更高,但是他有一个无法避免的缺点,就是内存无法存储我们的数据,比如你正在操作数据的同时,突然断电了或者宕机了 ,内存存入的数据都会丢失,它并没有办法存储我们的数据,Redis提供了一个磁盘持久化的功能,通过磁盘持久化的功能,可以把内存中的数据持久化到磁盘中去
持久化方案:
1.使用bgsave命令
比如使用2窗口:设置添加一条数据
客户端存入数据:
1窗口演示宕机或者关机,以杀死进程为例:然后再重新启动
再次查看客户端:数据不在了
说明内存无法存储数据
输入后台保存的命令bgsave:把数据存入到磁盘里面去,即使这时候1窗口演示宕机,数据也会存在
bgsave命令:优点:比较简单,只需要输入bgsave命令,就可以把数据持久化到磁盘上面去
缺点:需要频繁的使用这个命令,还是优点麻烦的
(13)Redis持久化方案-rdb
rdb持久化方案:
通过redis.conf里观看:
持久化文件夹dump.rdb
dir ./当前目录
save 900 1:表示只要900秒只要有一个key发生变化,就会把数据持久化到磁盘
可以添加一条
rdb方案优点:比较省心,只需要在配置文件做了配置就不需要动了,它会自动根据配置问价,自动化持久化数据到磁盘
缺点:rdb有可能还是会丢失数据的,比如58秒 10000个key 58秒的时候突然宕机了,10000个key根本没有保存进去没有保存到dump.rdb这个文件中去
(14)Redis持久化方案-aof
开启appendonly:改为yes, rdb方案就会失效
把输入的命令,会追加到appendOnly.aof这个文件中去,它是后台开启了一个线程,每当我们输入一条命令,这个线程就会把这条数据追加到appendonly.aof中去 ,当在启动的时候呢,它会先读取appendonly.aof中去,把aof中的命令读取出来,相当于把这个命令在敲一遍
aof优点:实时的记录我们的命令,把数据持久到我们的磁盘的
缺点:如果一段时间敲了十几万行命令,这个文件就变得非常大,启动的时候呢,在读取命令是非常缓慢的
在日常的项目中,需要看具体的情况,选择合适的方案。如果允许部分数据丢失,选择使用rdb方案。
如果不允许数据丢失,需要实时更新,选择aof方案
也可能把这两种方案结合