目录
3.3 RedisTemplate的RedisSerializer
一、基础篇
1.认识NoSQL
①数据结构:非结构化 key-value型、Document型、Graph型
②数据关联:无关联的
③查询方式:非SQL
④事务特性:BASE(BA基本可用 、 S允许中间态 、 E最终一致性)
⑤存储方式:内存
⑥扩展性:水平
⑦使用场景:数据结构不固定、对一致性安全性要求不高、对性能要求
2.认识Redis
2.1特征:
①键值型,value支持多种不同数据结构,功能丰富
②单线程,每个命令具备原子性
③低延迟、速度快(基于内存、IO多路复用、良好的编码)
④支持数据持久化
⑤支持主从集群、分片集群
⑥支持多语言客户端
2.2安装启动Redis
ps:楼主是在CentOS7上用Docker安装的,需要的朋友可看我Docker的文章
单机安装Redis(CentOS7下)
①安装Redis依赖
yum install -y gcc tcl
②进入/usr/local/src/
一般都放这目录下
③解压
tar -zxvf 压缩包名
④运行编译命令
make && make install
⑤默认安装路径是/usr/local/bin/,ll查看
⑥启动
最简单的启动:redis-server (前台启动,该界面如被关闭,则关闭redis)
如果想要后台启动,则必须修改Redis配置文件,在我们之前解压的redis安装包下(/usr/local/src/redis-6.2.6),名字叫redis.conf
最好先备份一份 cp redis.conf redis.conf.bck
开始修改 vi redis.conf
需要修改的一些配置:
#允许访问的地址,默认127.0.0.1,只能本地访问,修改为0.0.0.0则可在任意IP访问,生产环境不要设置0.0.0.0
bind 0.0.0.0
#守护进程,修改为yes即可后台运行
daemonize yes
#密码,设置后访问redis必须输入密码
requirepass 密码
#监听的端口
port 6379
#工作目录,默认是当前目录,也就是运行redis-server时的命令,日志、持久化等文件会保存在这个目录
dir .
#数据库数量,设置为1,代表只使用1个库,默认16个库,编号0-15
database 1
#设置redis能使用的最大内存
maxmemory 512mb
#日志文件,默认为空,不纪录日志,可指定日志文件名
logfile "redis.log"
开机自启:
#配置redis.service
vi /etc/systemd/system/redis.service
#具体配置文件查一下其他的文档
#配置完成后重新加载服务
systemctl daemon-reload
#设置开机自启
systemctl enable redis
#启动redis
systemctl start redis
#查看redis状态
systemctl status redis
#停止redis
systemctl stop redis
命令行客户端
redis-cli [options] [commands]
options:
-h 127.0.0.1 指定要链接的redis节点的IP地址
-p 6379 指定要链接的端口
-a 密码 指定redis的密码
commands:
ping 与redis服务端进行心跳测试,正常返回pong
ps:
#docker简单启动redis命令
docker run --name redis -d -p 6379:6379 redis的镜像id
#进入redis容器
docker exec -it 容器id /bin/bash
cd /usr/local/bin
redis-cli
#docker带redis.conf启动
docker run -p 6379:6379 --name redis -v /aloneRedis/redis.conf:/etc/redis/redis.conf -d 16ecd2772934 redis-server /etc/redis/redis.conf
2.3 Redis数据结构
Redis是一个key-value的数据库,key一般是String,不过value的类型多种多样:
#5种基本类型
String helloworld
Hash {name:"Jack",age:21}
List [A -> B -> C -> C]
Set {A,B,C}
SortedSet {A:1,B:2,C:3}
#特殊类型
GEO {A:(120.3,30.5)}
BitMap 0110110101110101011
HypperLog 0110110101110101011
2.4 Redis命令
2.4.1 通用命令
KEYS 查看符合模板的所有key
DEL 删除一个指定的key
EXISTS 判断key是否存在
EXPIRE 给一个key设置一个有效期,有效期到期时该key会被自动删除
TTL 查询剩余有效期
2.4.2 命令
① String
SET 添加一个键值对,如果存在则会覆盖
GET 获取一个key对应的value
MSET 批量添加
MGET 批量获取
INCR 让一个整型的key自增1
DECR 让一个整型的key自减1
INCRY 让一个整型的key自增并指定步长 例如 incry num 2 让num+2
INCRBYFLOAT 让一个浮点类型的数字自增并指定步长
SETNX 添加一个String类型的键值对,前提是这个key不存在,否则不执行
SETEX 添加一个String类型的键值对,并且指定有效期
② key的层级格式
允许多个单词形成层级结构,多个单词之间用":"隔开
例如 项目名:业务名:类型:id
③ Hash
HSET key field value 添加或者修改hash类型key的值
HGET key field 获取一个hash类型key的field的值
HMSET 批量添加多个hash类型key的field的值
HMGET 批量获取多个hash类型key的field的值
HGETALL 获取一个hash类型key中的field和value
HKEYS 获取一个hash类型的key中所有的filed
HVALS 获取一个hash类型的key中的所有的value
HINCRBY 让一个hash类型key的字段值自增并指定步长
HSETNX 添加一个hash类型的key的field值,前提是这个field不存在,不然不执行
④ List
LPUSH key element 从左边添加 LPUSH users 1 2 3
LPOP key element 从左边移除并返回 LPOP users 1 拿出3
RPUSH key element 从右边添加
RPOP key element 从右边移除并返回
LRANGE key start end 返回一段角标范围内的所有元素
BLPOP和BRPOP 与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil
⑤ Set
特征:无序、元素不可重复、查找快、支持交集并集差集等功能
SADD key member... 向set中添加一个或多个元素
SREM key member... 移除set中的指定元素
SCARD key 返回set中元素的个数
SISMEMBER key member 判断一个元素是否存在于set中
SINTER key1 key2 求k1和k2的交集
SDIFF key1 key2 求k1和k2的差集
SUNION key1 key2 求k1和k2的并集
⑥ SortedSet
是一个可排序的Set集合,与java中的TreeSet有些类似,但底层数据结构差距较大。
SortedSet中每一个元素中都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表加哈希表
特性:可排序、元素不重复、查询速度快
经常用来作排行榜
ZADD key score member 添加一个或多个元素到SortedSet,如果已经存在,更新score值
ZREM key member 删除SortedSet中一个指定的元素
ZSCORE key member 获取SortedSet中指定元素的Score值
ZRANK key member 获取SortedSet中指定元素的排名
ZCARD key 获取SortedSet中元素个数
ZCOUNT key min max 统计score值在给定范围内所有元素的个数
ZINCRBY key increment member 让SortedSet中的指定元素自增,步长为指定的increment值
ZRANGE key min max 按照score排序后,获取指定排名范围内的元素
ZRANGEBYSCORE key min max 按照score排序后,获取指定score范围内的元素
ZDIFF ZINTER ZUNION 求差集、交集、并集
所有排名默认升序,如果需要降序,在命令Z后面添加REV即可
3.Redis的Java客户端
Jedis:以Redis命令作为方法名称,学习成本低,简单实用。但是Jedis实例是线程不安全的,多线程环境下需要基于连接池来使用。
lettuce:Lettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式、集群模式和管道模式。
Redisson:Redisson是一个基于Reids实现的分布式、可伸缩的Java数据结构集合。包含了诸如Map、Queue、Lock、Semaphore、AtomicLong等强大功能。
3.1 Jedis
①导入依赖
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.3</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
②测试
public class JedisTest {
private Jedis jedis;
//初始化
@BeforeEach
void setUp(){
//连接Jedis
jedis = new Jedis("自己IP",6379);
//设置密码
jedis.auth("自己密码");
//选择库
jedis.select(0);
}
@Test
void testString(){
//存入数据
String result = jedis.set("name", "虎哥");
System.out.println("result="+result);
//获取数据
String name = jedis.get("name");
System.out.println(name);
}
@Test
void testHash(){
//插入Hash数据
jedis.hset("user:1","name","Jack");
jedis.hset("user:1","age","21");
//获取Hash数据
Map<String, String> map = jedis.hgetAll("user:1");
System.out.println(map);
}
@AfterEach
void testDown(){
if(jedis!=null){
jedis.close();
}
}
}
③Jedis连接池
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static {
//配置连接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//设置最大连接数
jedisPoolConfig.setMaxTotal(8);
//设置最大空闲连接,最多预留8个连接
jedisPoolConfig.setMaxIdle(8);
//设置最小空闲连接
jedisPoolConfig.setMinIdle(0);
//设置等待时长,最多等待1000ms
jedisPoolConfig.setMaxWaitMillis(1000);
//创建连接池对象
jedisPool = new JedisPool(jedisPoolConfig,
"自己IP",
6379,
1000,
"自己密码");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
配置连接池以后,测试程序的初始化就能写成:
//初始化
@BeforeEach
void setUp(){
jedis = JedisConnectionFactory.getJedis();
}
3.2 SpringDataRedis
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫SpringDataRedis。
SpringDataRedis快速入门:
redisTemplate.opsForValue() 返回值类型ValueOperations 操作String类型数据
redisTemplate.opsForHash() 返回值类型HashOperations 操作Hash类型数据
redisTemplate.opsForList() 返回值类型ListOperations 操作List类型数据
redisTemplate.opsForSet() 返回值类型SetOperations 操作Set类型数据
redisTemplate.opsForZSet() 返回值类型ZSe tOperations 操作SortedSet类型数据
① 引入依赖
SpringBoot默认整合了SpringDataRedis
<!--spring-data-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>
<!--Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
②配置文件
application.yml
spring:
redis:
host: 自己IP
port: 6379
password: 自己密码
database: 0
lettuce:
pool:
max-active: 8 #最大连接
max-idle: 8 #最大空闲连接
min-idle: 0 #最小空闲连接
max-wait: 1000ms #等待时长
③注入RedisTemplate 开始使用
@SpringBootTest
public class RedisTemplateTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
void testString(){
//写入一条String数据
redisTemplate.opsForValue().set("name","Jack");
//获取一条String数据
Object name = redisTemplate.opsForValue().get("name");
System.out.println("name="+name);
}
}
3.3 RedisTemplate的RedisSerializer
点RedisTemplate进入源码查看,默认是JDK的序列化器,底层是ObjectOutputStream
这种情况可读性差、占用空间大
还有两种支持的序列化器:StringRedisSerializer和GenericJackson2JsonRedisSerializer
key一般用StringRedisSerializer
value一般用GenericJackson2JsonRedisSerializer
创建一个配置Bean
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
//创建RedisTemplate对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//设置连接工厂
redisTemplate.setConnectionFactory(connectionFactory);
//创建Json的序列化工具
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//设置key的序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
//设置value的序列化
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
//返回
return redisTemplate;
}
}
配置完成以后在需要使用RedisTemplate的地方注入即可
@Autowired
private RedisTemplate<String,Object> redisTemplate;
写入对象进行测试:
首先创建一个对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
}
@Test
void testSaveUser(){
// 写入数据
redisTemplate.opsForValue().set("user:100",new User("中国人",22));
// 获取数据
User user = (User)redisTemplate.opsForValue().get("user:100");
System.out.println("user="+user);
}
通过Redis图形化界面发现序列化成功
但是有个问题,里面存着“@class”,占用比较大,这时候我们就需要进行手动序列化和反序列化
用Spring默认提供的SpringRedisTemplate类,它的key和value序列化方式都是String方式,省去我们自定义RedisTempate的过程。
@SpringBootTest
public class StringRedisTemplateTest {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void testString(){
//写入一条String数据
stringRedisTemplate.opsForValue().set("name","我是中国人呀");
//获取一条String数据
Object name = stringRedisTemplate.opsForValue().get("name");
System.out.println("name="+name);
}
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
//创建对象
User user = new User("张某人", 22);
// 手动序列化
String json = mapper.writeValueAsString(user);
// 写入数据
stringRedisTemplate.opsForValue().set("user:200",json);
// 获取数据
String jsonValue = stringRedisTemplate.opsForValue().get("user:200");
// 手动反序列化
User userResult = mapper.readValue(jsonValue, User.class);
System.out.println("userResult="+userResult);
}
}
操作Hash类型数据
@Test
void testHash(){
stringRedisTemplate.opsForHash().put("user:400","name","用户400");
stringRedisTemplate.opsForHash().put("user:400","age","20");
Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:400");
System.out.println("entries="+entries);
}