一,准备工作
1.创建工程
创建maven父工程,例如03-sca-redis,并在此工程下创建两个子工程,一个为sca-jedis,一个为sca-tempate,例如:
2.添加项目依赖
sca-jedis 工程依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
添加sca-template工程依赖
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.2.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
二,Jedis的应用
1.简介
Jedis是Java中操作redis的一个客户端,类似通过jdbc访问mysql数据库。
2.准备工作
第一步:从redis.io官方下载对应版本的redis.conf文件,地址如下
官方下载
第二步:停止redis并删除或者覆盖挂载目录下(/usr/local/docker/redis01/conf)的redis.conf配置文件.
停止redis服务
执行命令 docker inspect redis01 (我这里redis容器的名称设置为redis01),查看其挂载位置
第三步:将下载的redis.conf文件拷贝到redis挂载目录(/usr/local/docker/redis01/conf)
转到指定目录,因为现在存在的redis.conf是我们一开始创建的空的文件,所以,直接拖拽,覆盖该文件就好
第四步:基于vim打开redis.conf文件,然后注释 bind 127.0.0.1(不只限于本机使用)这一行,并修改protected-mode的值修改为no(将保护认证关闭,否则不经过认证,无法访问).,或者将该行注释一样的效果。
进入对应目录,打开redis.conf文件
进入文件后,按i进入编辑模式
按esc,:wq保存退出
第五步:重启redis服务,并检查启动日志(docker logs 容器id)
3.快速入门实现
在Jedis工程中定义单元测试类,在类中定义单元测试方法:
连接测试
@Test
public void testGetConnection() {
Jedis jedis = new Jedis("192.168.126.128",6379);
//jedis.auth("123456");//假如设置了密码还要执行这个语句
String ping = jedis.ping();
System.out.println(ping); //PONG
}
注意:这里的ip地址对应你redis所在容器的地址,我这里是192.168.126.128
字符串类型测试
@Test
public void testStringOper() throws InterruptedException {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.向redis存储string类型数据
jedis.set("id","1");
jedis.set("name","Tony");
jedis.set("token", UUID.randomUUID().toString());
jedis.expire("token",2); //设置存在时长
//3.更新redis中指定数据
jedis.set("id","100");
jedis.incr("id"); //自增 101
jedis.incrBy("id",2); //自增 + 2 103
jedis.decr("id"); //自减 102
//4.删除redis中指定数据
jedis.del("name");
//5.查看redis中的数据
String id = jedis.get("id");
//Thread.sleep(2000);
TimeUnit.SECONDS.sleep(1); //同上,休眠1s
String token = jedis.get("token");
Long strLen = jedis.strlen("token");
String name = jedis.get("name");
System.out.println("id = " + id);
System.out.println("token = " + token);
System.out.println("token.length = " + strLen);
System.out.println("name = " + name);
//6.释放资源
jedis.close();
}
当休眠时间设置的是 >= 2s 时,则token就不存在
Hash类型的测试
//对Hash类型的测试
@Test
public void testHashOper() {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.向redis存储数据
jedis.hset("user","id","100");
jedis.hset("user","name","drh");
jedis.hset("user","age","man");
jedis.hset("user","mobile","11111111111");
//3.更新redis中指定数据
jedis.hset("user","id","101");
//4.删除redis中指定数据
jedis.hdel("user","age","mobile");
//5.查看redis中的数据
String id = jedis.hget("user", "id");
System.out.println("user.id = " + id);
Map<String,String> user = jedis.hgetAll("user");
System.out.println("user = " + user);
//6.释放资源
jedis.close();
}
Hash直接存取map对象
/**直接存取map对象*/
@Test
public void testHashOper02() {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.存储一个map对象
Map<String,String> map = new HashMap<>();
map.put("x","100");
map.put("y","200");
jedis.hset("point",map);
//3.读取一个map对象
Map<String,String> point = jedis.hgetAll("point");
System.out.println(point);
}
对json类型数据的测试
//对json类型数据的测试
/**
* 将对象转换为json字符串,再存储到redis中
* 这种方式的最大弊端就是修改数据不方便,需要先修改map,然后再转换为json字符串,再存储
*/
@Test
public void testStringJsonOer() {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.将对象转换为json字符窜
Map<String,Object> map = new HashMap<>();
map.put("id","101");
map.put("name","drh");
Gson gson = new Gson(); //Google公司提供
String jsonStr = gson.toJson(map); //将map转换为json串
System.out.println("jsonStr = " + jsonStr);
//3.将json字符窜存储到redis
jedis.set("member",jsonStr);
//4.取出member对象的值
String member = jedis.get("member");
System.out.println("member = " + member);
//5.将json字符窜转换为Map对象
map = gson.fromJson(member,Map.class);
System.out.println(map);
//6.释放资源
jedis.close();
}
list类型测试
//list类型测试
@Test
public void testListOper01() {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.存储数据(list集合有顺序,允许重复)
jedis.lpush("lst1","A","B","C","C");
//3.修改数据
//3.1首先获取要修改的元素的下表
Long index = jedis.lpos("lst1","A");
//3.2基于下表,修改元素内容
jedis.lset("lst1",index,"D");
//4.删除数据
//5.查询数据
List<String> lst1 = jedis.lrange("lst1",0,-1);
System.out.println(lst1);
//6.释放资源
jedis.close();
}
list阻塞队列
/**
* 阻塞式队列
*/
@Test
public void testListOper02() {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.存储数据
jedis.lpush("lst2","A","B","C");
//3.按先进先出的顺序从队列取数据
List<String> list = jedis.brpop(40,"lst2");
System.out.println(list);
jedis.brpop(40,"lst2");
jedis.brpop(40,"lst2");
jedis.brpop(40,"lst2");
//4.释放资源
jedis.close();
}
当lst2中数据全部删除后,阻塞了40s
set类型测试
//set类型测试
@Test
public void testSetOper() {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.存储数据(Set集合没有顺序,不允许重复)
jedis.sadd("set1","A","A","B","C","D ");
//3.修改数据
//4.删除数据
jedis.spop("set1"); //随机删除一个元素
jedis.srem("set1","B");
//5.查询数据
Set<String> set1 = jedis.smembers("set1");
System.out.println(set1);
Long cards = jedis.scard("set1");
System.out.println(cards); //查看元素个数
//6.释放数据
jedis.close();
}
4.简易功能实现
单点登录
业务描述
在分布式系统中,通过会有多个服务,我们登录了一个服务以后,再访问其它服务时,不想再登录,就需要有一套单独的认证系统,我们通常会称之为单点登录系统,在这套系统中提供一个认证服务器,服务完成用户身份认证,在一些中小型分布式系统中中,我们通常会借助redis存储用户的认证信息,例如:
关键代码
package com.jt.redis;
import redis.clients.jedis.Jedis;
import java.util.UUID;
/**
* SSO 案例演示:
* 1)访问资源(假如没有登录,要提示先登录,如何判定是否登录了)
* 2)执行登录(登录成功,要将登录用户信息写入到redis)
* 3)访问资源(登录ok,从redis获取token值信息)
* 解决方案
* 1) SpringSecurity + jwt + oauth2
* 2) SpringSecurity + redis + oauth2(中小型并发)
*/
public class SSODemo01 {
/**认证中心的登录设计*/
static String doLogin(String username,String password) {
//1.执行用户身份校验
if (!"jack".equals(username))
throw new IllegalArgumentException("这个用户不存在");
//2.用户存在并且密码正确,表示用户是系统的合法用户
if (!"123456".equals(password))
throw new IllegalArgumentException("密码不正确");
//3.将合法用户信息存储到redis
Jedis jedis = new Jedis("192.168.126.128",6379);
String token = UUID.randomUUID().toString();
jedis.set(token,username);
jedis.expire(token,10); //数据只允许存在10s
jedis.close();
return token;//token
}
/**获取资源服务中的资源*/
static String doGetResource(String token) {
//1.检查用户是否已经登录
if (token == null || "".equals(token))
throw new IllegalArgumentException("请先登录");
Jedis jedis = new Jedis("192.168.126.128",6379);
String username = jedis.get(token);
jedis.close();
//2.假如没有登录,则表示先登录
if (username == null)
throw new RuntimeException("登录已超时,请重新登录");
//3.已登录可以访问资源
System.out.println("继续访问资源");
return "the resource of user";
}
//客户端
public static void main(String[] args) throws InterruptedException {
String token = null;
//第一次访问资源
doGetResource(token);
//执行登录操作
token = doLogin("jack","123456");
//第二次访问资源
//Thread.sleep(10000);
doGetResource(token);
}
}
运行结果
当我们模仿第一次访问资源时
当我们模拟登录后访问资源
当我们模拟登录时长超过10s时
简易分布式id生成策略
业务描述
在分布式系统中,数据量将越来越大时,就需要对数据进行分表操作,但是,分表后,每个表中的数据都会按自己的节奏进行自增,很有可能出现ID冲突。这时就需要一个单独的机制来负责生成唯一ID,生成出来的ID也可以叫做 分布式ID,这里我们借助redis实现一个简易的分布式id进行实现,当然还有一些第三方的系统,可以帮你生成这样的id,可以自己进行拓展学习
关键代码
package com.jt.redis;
import redis.clients.jedis.Jedis;
public class IdGenerator {
/**
* 编写一个方法,每次调用此方法
* 外界都能够获取一个唯一的一个递增
* 整数值
*/
public static Long getId() {
Jedis jedis = new Jedis("192.168.126.128",6379);
//incr方法用于对指定key的值进行递增,假如key不存在,则自动创建
long id = jedis.incr("incrementId");
jedis.close();
return id;
}
public static void main(String[] args) {
for (int i = 0;i < 10;i++) {
new Thread() {
@Override
public void run() {
System.out.println(IdGenerator.getId());
}
}.start();
}
}
}
再执行一次
简易秒杀队列
业务描述
在设计一个秒杀或抢购系统时,为了提高系统的响应速度,通常会将用户的秒杀或抢购请求先存储到一个redis队列,这里我们就基于redis实现一个先进先出队列,例如:
关键代码
import java.util.List;
/**
* 演示抢购活动中的秒杀队列
* 数据逻辑结构:list
* 算法:FIFO(公平性)
* 在抢购活动中会执行这样的操作
* 1)生产者(购买商品的用户):创建请求并将请求存储到队列
* 2)消费者(处理购买请求的底层对象):从队列取请求,然后处理请求
*/
public class SecondsKillDemo01 {
public static void main(String[] args) {
//1.构建生产者(购买商品的用户)
Thread t1 = new Thread() {
@Override
public void run() {
int i = 1;
for (;;) {
enqueue("request-" + i++);
try {
Thread.sleep(1000); //1s一个线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//2.构建消费者(处理请求的对象)
Thread t2 = new Thread() {
@Override
public void run() {
for (;;) {
String request = dequeue();
if (request == null) continue;
System.out.println("process " + request);
}
}
};
//3.开启抢购活动
t1.start();
t2.start();
}
/**
* 入队操作
*/
public static void enqueue(String request) {
Jedis jedis = new Jedis("192.168.126.128",6379);
jedis.lpush("queue-1",request);
jedis.close();
}
/**
* 出队操作
*/
public static String dequeue() {
Jedis jedis = new Jedis("192.168.126.128",6379);
//非阻塞式取数据
//return jedis.rpop("queue-1");
//阻塞式取数据
List<String> request = jedis.brpop(60,"queue-1"); //返回{"queue-1","request-x"}
jedis.close();
return request != null ? request.get(1) : null; //下表为0的时key 即queue-1
}
}
运行结果
简易投票系统
业务描述
在很多系统中设计中,都会有一个活动设计,开启一个活动之前,可以对这个活动的支持力度先进行一个调查,例如基于这个活动设计一个投票系统,例如:
关键代码
package com.jt.redis;
import redis.clients.jedis.Jedis;
import java.util.Set;
/**
* 投票系统演示:模拟基于某个活动的投票程序
* 业务说明:一个用户只能投票一次(不允许重复)
* 数据结构设计:基于redis的set类型进行数据存储
*/
public class VoteDemo01 {
//进行投票(key为活动id,value为userId)
public static void vote(String activityId,String userId) {
Jedis jedis = new Jedis("192.168.126.128",6379);
jedis.sadd(activityId,userId);
jedis.close();
}
//查看投票次数
public static Long getVoteCount(String activityId) {
Jedis jedis = new Jedis("192.168.126.128",6379);
Long count = jedis.scard(activityId);
jedis.close();
return count;
}
//查看这个活动被哪些用户投过票
public static Set<String> getVoteUsers(String activityId) {
Jedis jedis = new Jedis("192.168.126.128",6379);
Set<String> smembers = jedis.smembers(activityId);
jedis.close();
return smembers;
}
//检查这个用户是否已对这个活动投过票
public static Boolean checkVote(String activityId,String userId) {
Jedis jedis = new Jedis("192.168.126.128",6379);
Boolean flag = jedis.sismember(activityId,userId);
jedis.close();
return flag;
}
//模拟投票客户端
public static void main(String[] args) {
//1.初始化
String activityId = "10001";
String user1 = "201";
String user2 = "202";
String user3 = "203";
//2.投票
vote(activityId,user1);
vote(activityId,user2);
vote(activityId,user3);
vote(activityId,user3);
//3.获取投票次数
Long voteCount = getVoteCount(activityId);
System.out.println("投票次数:" + voteCount);
//4.输出哪些人投过票
Set<String> users = getVoteUsers(activityId);
System.out.println(users);
//5.检查用户是否投过票
boolean flag = checkVote(activityId,user1);
System.out.println(user1 + ":" + (flag ? "已投过票" : "还没投票"));
}
}
运行结果
简易购物车实现
业务描述
简易购物车业务设计如图所示:
基础指令操作,例如:
1)向购物车添加商品
hset cart:101 2001 1
hset cart:101 2002 1
hset cart:101 2003 2
2)查看购物车商品
hgetall cart:101
3)删除购物车商品
hdel cart:101 2003
4)改变购物车某个商品的购买数量
hincrby cart:101 2002 2
关键代码
package com.jt.redis;
import redis.clients.jedis.Jedis;
import java.util.Map;
/**
* 基于redis存储商品购物车信息
*/
public class CartDemo01 {
//添加商品
public static void addCart(Long userId,Long productId,int num) {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.向购物车添加商品
//hincrBy这个函数在key不存在时会自动创建key
jedis.hincrBy("cart:" + userId,String.valueOf(productId),num);
//3.释放redis链接
jedis.close();
}
//查看我的购物车
public static Map<String,String> listCart(Long userId) {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.查看购物车商品
Map<String,String> map = jedis.hgetAll("cart:" + userId);
//3.释放redis链接
jedis.close();
return map;
}
//删除某些商品
public static void doDelCart(Long userId,String ...productId) {
//1.建立连接
Jedis jedis = new Jedis("192.168.126.128",6379);
//2.清除指定商品
jedis.hdel("cart:" + userId, productId);
//3.释放资源
jedis.close();
}
//模拟购物车
public static void main(String[] args) {
//1.向购物车添加商品
addCart(1L,201L,1);
addCart(1L,202L,1);
addCart(1L,203L,2);
//2.查看购物车商品
Map<String,String> map = listCart(1L);
System.out.println("刚开始购物车:");
System.out.println(map);
//3.清除购物车
doDelCart(1L,"201","203");
map = listCart(1L);
System.out.println("删除商品后购物车");
System.out.println(map);
}
}
运行结果
第一次执行
第二次执行
已发生递增
当添加删除操作后
5.连接池JedisPool应用
我们直接基于Jedis访问redis时,每次获取连接,释放连接会带来很大的性能开销,可以借助Jedis连接池,重用创建好的连接,来提高其性能,简易应用方式如下:
先做测试
package com.jt;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* 测试jedis连接池的一个基本应用
*/
public class JedisPoolTests {
@Test
public void testJedisPool() {
//1.构建jedis连接池
//1.1定义连接池配置
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(16);//最大连接数默认为8
config.setMaxIdle(60);//最大空闲时间(连接后续不用了,超出一定空闲时间要释放)
//1.2定义连接的url和端口
String host = "192.168.126.128";
int port = 6379;
//1.3创建连接池
JedisPool jedisPool = new JedisPool(config,host,port);
//2.从池中获取连接(jedis对象)
Jedis resource = jedisPool.getResource();
//3.执行redis操作
resource.set("pool","JedisPool");
String pool = resource.get("pool");
System.out.println(pool);
//4.释放资源(不是关,而是将连接还回池中)
resource.close();
//5.关闭池(一般服务停止时关)
//jedisPool.close();
}
}
测试结果
我们可以基于池对象,设计一个数据源,将来在业务中通过一个数据源对象,从池中获取连接,不用每次获取连接都要创建池对象,例如:
package com.jt.redis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisDataSource {
private static final JedisPool jedisPool;
private static final String HOST = "192.168.126.128";
private static final int PORT = 6379;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(16);//最大连接数,默认为8
config.setMaxIdle(60);
jedisPool = new JedisPool(config,HOST,PORT);
}
/**
* 获取一个连接对象
* @return
*/
public static Jedis getConnection() {
return jedisPool.getResource();
}
public static JedisPool getJedisPool() {
return jedisPool;
}
}
这样我们在连接时,只需要调用这个方法即可
5.StringRedisTemplate 应用
配置application.yml文件
并且打开对应ip和端口的redis服务。
StringRedisTemplate 是一个专门用于操作redis字符串类型数据的一个对象,其应用方式如下:
package com.cy.redis;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
public class StringRedisTemplateTests {
/**
* 此对象 操作redis的一个客户端对象,这个对象
* 对key/value采用了字符串的序列化方式进行
* redis数据的读写操作
*/
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void testGetConnection() {
RedisConnection connection = stringRedisTemplate.getConnectionFactory().getConnection();
String ping = connection.ping();
System.out.println(ping);
}
@Test
public void testStringOper01() {
//1.获取字符串操作对象
ValueOperations<String,String> vo = stringRedisTemplate.opsForValue();
//读写redis中的数据
vo.set("x","100");
String x = vo.get("x");
System.out.println("String类型测试1");
System.out.println(x);
}
@Test
public void testStringOper02() throws JsonProcessingException {
//获取字符串操作对象
ValueOperations<String,String> vo = stringRedisTemplate.opsForValue();
//2.读写redis中的数据
Map<String,String> map = new HashMap<>();
map.put("id","01");
map.put("name","drh");
//将map对象转换为json字符串写到redis数据库
String jsonStr = new ObjectMapper().writeValueAsString(map);
vo.set("blog",jsonStr);
jsonStr = vo.get("blog");
System.out.println("String类型测试2");
System.out.println(jsonStr);
map = new ObjectMapper().readValue(jsonStr,Map.class);
System.out.println(map);
}
@Test
public void testHashOper01() {
//1.获取hash操作
HashOperations<String,Object,Object> vo = stringRedisTemplate.opsForHash();
//2.读取redis数据
//2.1 存储一个对象
vo.put("user","id","100");
vo.put("user","username","drh");
vo.put("user","status","1"); //注意这里1必须是字符串形式
//2.2获取一个对象
//2.2.1获取对象某个属性的值
Object username = vo.get("user","username");
System.out.println("Hash类型测试");
System.out.println(username);
//2.2.2获取对象所有的值
List<Object> user = vo.values("user");
System.out.println(user);
}
}
注意导包别导错了
运行结果:
6.RedisTemplate 应用
RedisTemplate是一个专门用于实现对远端redis中复杂数据的操作的对应,应用案例如下:
package com.cy.redis;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.xml.transform.Source;
import java.util.*;
@SpringBootTest
public class RedisTemplateTests {
//这个对象在spring boot工程的RedisAutoConfiguration类中已经做了配置
//此对象在基于redis存储数据时默认采用序列化的方式
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testGetConnection() {
RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
String ping = connection.ping();
System.out.println("连接测试");
System.out.println(ping);
}
/**
* 测试String类型的数据
*/
@Test
public void testStringOper01() {
//自己指定key/value序列化方式
//redisTemplate.setKeySerializer(new StringRedisSerializer());
//redisTemplate.setValueSerializer(new StringRedisSerializer());
ValueOperations vo = redisTemplate.opsForValue();
//key和value默认会采用JDK的序列化的方式进行存储
vo.set("token", UUID.randomUUID().toString());
Object token = vo.get("token");
System.out.println("String类型测试");
System.out.println(token);
}
/**
* 测试hash类型的数据
*/
@Test
public void testHashOper01() {
//1.获取操作hash类型数据的操作对象
HashOperations ho = redisTemplate.opsForHash();
//2.读写redis数据hash类型数据
Map<String,Object> map = new HashMap<>();
map.put("id",100);
map.put("title","spring boot");
//直接存储一个map
ho.putAll("blog",map); //hash存储 序列化
//存储单个字段,值
ho.put("blog","content","spring boot redis");
//取blog对象中id属性的值
Object o = ho.get("blog", "id");
System.out.println("Hash类型测试");
System.out.println("id = " + o);
//获取整个blog对象所有属性和值
Map blog = ho.entries("blog"); //反序列化
System.out.println(blog);
}
/**
* 测试list类型的数据
*/
@Test
public void testListOper01() {
//1.获取操作list类型数据的操作对象
ListOperations lo = redisTemplate.opsForList();
//2.读写redis数据list类型数据
lo.leftPush("lst1","A");
lo.leftPushAll("lst1","B","C","D","D");
//取数据
List lst1 = lo.range("lst1", 0, -1);
System.out.println("List类型测试");
System.out.println(lst1);
}
@Test
public void testSetOper01() {
//1.获取操作list类型数据的操作对象
SetOperations so = redisTemplate.opsForSet();
//2.读写redis数据set类型数据
so.add("set1","A","B","C","C"); //不允许重复
Set set = so.members("set1");
System.out.println("set类型测试");
System.out.println(set);
}
}
注意导包
运行结果,首先观察一个现象。我们测试String类型时,查看redis数据库时,如下图
key和value默认会采用JDK的序列化方式进行存储
如果需要在数据库中也显示我们存入的数据,需要自己设置序列化的方式
7.定制RedisTemplate对象
对于系统默认的RedisTemplate默认采用的是JDK的序列化机制,假如我们不希望实用JDK的序列化,可以采用的定制RedisTemplate,并采用自己指定的的序列化方式,例如:
package com.jt.redis.config;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
//1.构建RedisTemplate对象
RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
//2.设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
//3.定义序列化方式(在这里选择jackson)
Jackson2JsonRedisSerializer redisSerializer= new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper=new ObjectMapper();
//设置要序列化的域(属性)
//any表示任意级别访问修饰符修饰的属性 private,public,protected
objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
//启动输入域检查(类不能是final修饰的)
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY);
redisSerializer.setObjectMapper(objectMapper);
//4.设置RedisTemplate的序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(redisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(redisSerializer);
//spring规范中假如修改bean对象的默认特性,建议调用一下afterPropertiesSet()
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}