redis笔记
发布日期:2022-09-29 16:50:48 浏览次数:1 分类:技术文章

本文共 31846 字,大约阅读时间需要 106 分钟。

cache缓存

什么是缓存?为什么用缓存?

程序运行中在内存保持必定时间不变的数据就是缓存

简单来说Map ,List,Array 等存放的数据可以理解为缓存

所以缓存并不是什么高大上的技术,仅仅是一个概念在程序的角度缓存可以理解为存放数据的容器

思考:要设计一个缓存,基本功能存和取:

  1. 能在缓存中存放数据
  2. 能在缓存取出数据

分析:

​ 缓存中存取数据一系列问题

1. 区数据时判断缓存中是否存在,,若不存在就从数据库查询,再将数据存入缓存中	2. 数据不一致缓存与数据库不一致	3. 多个缓存的情况

为了解决这些问题更智能化管理缓存缓存框架就由此而来 SpringCache,memacache,redis ,monggoDB(NOSQL)

NOSQL:Not Only SQL 非关系型数据库

不依赖业务逻辑方式存储 AOP切面编程 非入侵式以简单的key value 存储相对灵活机动大大增加了数据库的扩展能力

NOSQL使用场景:

对数据高并发的读写

对海量数据的读写操作

对数据高扩展性

不适用缓存:需要事务支持,基于SQL结构化查询存储

概念
SpringBoot Cache

可以有效降低数据库压力提升整个系统响应效率和并发量

一般使用思路:

如果缓存存在数据,就从缓存取数据,如果缓存不存在数据就从数据库读取

实现原理:

​ 利用SpringAop动态代理,在项目启动时动态生成代理类,实现对应的逻辑,从Spring3.1之后定义了Cache缓存框架和CacheManager(缓存管理器)来统一不同缓存技术接口的实现,并支持基于注解的缓存方式

Cache接口:

  1. 为缓存的组件规范定义(包含缓存的各种集合操作)
  2. 使用spring缓存是抽象时只需要关注以下两点
    1. 确认方法需要被缓存以及缓存的策略
    2. 从缓存中读取之前缓存存储的数据
springcache的使用三步骤”:
  • 加依赖
org.springframework.boot
spring-boot-starter-cache
  • 开启缓存
@SpringBootApplication //(exclude = DataSourceAutoConfiguration.class)//启动项目不加载数据库@EnableCaching //开启缓存注解public class Springbootdemo1Application {
//springBoot项目的主配置类 public static void main(String[] args) {
SpringApplication.run(Springbootdemo1Application.class, args); }}
  • 加缓存
spring框架自带的缓存:

Redis (单线程)session共享

依赖:

org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
2.3

读11万次 写8万次

通过配置文件启动服务端

redis-server lconfig/redis.conf:以配置文件启动

启动客户端

切换端口::redis-cli -p6379

查看redis进程

ps -ef|grep redis

客户端关闭服务:shutdown结束 exit退出

key命令
  1. 模糊查询 根据指定的规则查询符合条件的
Eg:keys pattern参数 (keys k*) //模糊查询 根据指定的规则查询符合条件的
  1. 删除某个key 删除多个key值是原子性操作
Eg:del key值(del k1)//删除某个key 删除多个key值是原子性操作
  1. exists 判断是否存在key值
Eg:127.0.0.1:6379> exists k3   (integer) 1
  1. move移动key到指定库索引(indexdb)
Eg:127.0.0.1:6379> move zengbao 2(integer) 1
  1. rename(rename key newKey)

  2. renamenx(rename key newKey)当newkey不存在时才能改名成功,存在就修改失败

  3. type(type key)判断key的类型

Eg:127.0.0.1:6379> type k3string
  1. expire(指定过期时间) expire key second
Eg:127.0.0.1:6379> expire zengbao 30(integer) 1127.0.0.1:6379> ttl zengbao(integer) 24
  1. expireat(expireat key timestamp) 以时间戳的形式设置key的过期时间
Eg:127.0.0.1:6379> expireat k3 1641516670(integer) 1
  1. pexpireat(pexpireat key timestamp )以毫秒的形式设置key的过期时间跟上面的不一样
Eg:127.0.0.1:6379> pexpireat k3 1641516670(integer) 1
  1. persist (persist key )移除key的失效时间
  2. ttl 计算key还有多少时间失效,返回key剩余失效时间(返回-2 表示key不存在 ,-1永不过时)
  3. pttl (pttl key )以毫秒为单位返回key的失效时间
  4. randomkey (randomkey key) 随机获取一个key值
  5. dump (dump key)对key序列化(序列化给定key)
String字符串类型

string是Redis中最基本的数据类型,一个Key对应一个value。String类型是二进制的,可以包含任何数据

Eg:数字,字符串,图片,序列化的对象

应用场景:统计网站访问量,在线人数

session共享解决方案:SpringSession+redis实现

  • 常用方法
    • incr (incr key number )
    • incrby (incrby key number) incrby key 负数 就减
    • decr (decr key number )
    • decrby (decrby key number) decrby key 负数 就增
    • append(append key value)给指定key追加value
Hash类型

Hash类型可以理解为Mapmap,本身就是一种键值对结构,value值又是一个Map结构,将多个key value 存在key中(散列)

应用场景:存储,读取,修改属性操作

添加多个hash

127.0.0.1:6379> hmset user id 1 name zengbao age 2//设置多个OK127.0.0.1:6379> hget user name//设置一个"zengbao"127.0.0.1:6379> hmget user name //查询多个1) "zengbao"

查看一整个Hash表属性key和value

127.0.0.1:6379> hgetall user1) "id"2) "1"3) "name"4) "zengbao"5) "age"6) "2"

判断有多少个属性

127.0.0.1:6379> hlen user(integer) 3

查询Hash表key属性中是否存在

127.0.0.1:6379> hexists user name(integer) 1

查询Hash表所有属性key

127.0.0.1:6379> hkeys user1) "id"2) "name"3) "age"

查询Hash表所有value值

127.0.0.1:6379> hvals user1) "1"2) "zengbao"3) "2"

删除Hash表中的一个属性

127.0.0.1:6379> hdel user age(integer) 1

添加并判断是否存在若存在则添加失败(hsetnx key field value)

127.0.0.1:6379> hsetnx user age 2(integer) 1

hincrby/hincrbyfloat key field incrment(给hash表key执行字段的整数值/浮点值添加 incrment)

127.0.0.1:6379> hincrby user age 20(integer) 22127.0.0.1:6379> hincrbyfloat user price 6.8#浮点型"13.6"
List(链表)类型

list就是链表,在redis中List使用双端链表来实现,结构是有序的value值可以重复,可以通过下标取出对应value值,左右两边都能 进行插入和删除数据

应用场景:排行榜、消息队列、timeline微博时间轴(有人发微博就Lpush进去,加入时间轴展示新的列表信息)

List列表允许用户从序列的两端插入和弹出元素,列表是由多个字符串组成的有序可重复的序列,所以两端的操作效率比较高

常用方法:

  • 插入操作

    LPUSH(队列头左插入)、RPUSH(队列尾右插入)、Lrange(读取操作) 插入顺序和读取顺序相反

    #左插入27.0.0.1:6379> lpush listdemo 1 2 3 4 5 6(integer) 6#查询127.0.0.1:6379> lrange listdemo 0 -1 倒序  0 -2 就是6 到21) "6"2) "5"3) "4"4) "3"5) "2"6) "1"#右插入127.0.0.1:6379> rpush listdemo 1 2 3 4 5 6(integer) 12127.0.0.1:6379> lrange listdemo 0 -1 #索引 表示查询全部 1) "6" 2) "5" 3) "4" 4) "3" 5) "2" 6) "1" 7) "1" 8) "2" 9) "3"10) "4"11) "5"12) "6"
  • 弹出操作

    lpop:栈顶,后进先出,rpop:栈尾,先进先出

    lpop/rpop

    127.0.0.1:6379> lpop listdemo"6"127.0.0.1:6379> rpop listdemo"6"
  • 按照索引获取元素

    lindex

    127.0.0.1:6379> lindex listdemo 2"3"
  • 获取列表长度

    llen

    127.0.0.1:6379> llen listdemo(integer) 10
  • 删除N个value

    lrem key value

    127.0.0.1:6379> lrem listdemo 2 3#删除两个三(integer) 2 #返回删除元素个数  如果没有指定的值返回0
  • 截取指定范围值后并再赋值

    ltrim key start end (包含边界)#截取前127.0.0.1:6379> lrange listdemo 0 -11) "5"2) "4"3) "2"4) "1"5) "1"6) "2"7) "4"8) "5"127.0.0.1:6379> ltrim listdemo 0 2OK#截取后127.0.0.1:6379> lrange listdemo 0 -11) "5"2) "4"3) "2"
  • rpoplpust

    将一个列表的最后一个元素添加到另外一个列表

    #rpoplpust 原列表 目标列表127.0.0.1:6379> rpoplpush listdemo listdemo2"2"
  • 改变列表的值

    #lset key index value127.0.0.1:6379> lset listdemo2 1 3OK127.0.0.1:6379> lrange listdemo2 0 -11) "2"2) "3"3) "2"4) "1"
  • 再目标值前/后插入value

    #linsert key before/after 目标值 value 127.0.0.1:6379> linsert listdemo2 after 3 8(integer) 5
  • set类型

    以无序的方式存储多个不同的元素【无序,不重复】,除了对集合能快速执行添加,删除,检查元素是否存在之外,还可以对多个集合执行交集,并集,差集的操作,set集合类型底层的数据结构是数字字典

    数字字典:其实就是键值对(key value pairs )组合各个键值对的键各不相同,程序可以添加新的键值对到数字字典中,基于键进行查询,更新或删除等操作

    key、value、//map

    key、value null//数字字典结构

    redis的set集合,在使用数字字典结构保存数据时、他会将元素保存到字典键值中,而字典的值统一设置为null

    应用场景:

    1. 利用交集求共同好友
    2. 唯一性操作,可以统计访问网站的所有独立IP

    常用方法:

    1. 添加、查询、是否存在

      #add/smembers/sismember key member127.0.0.1:6379> sadd set1 1 2 3 4 5(integer) 5127.0.0.1:6379> smembers set11) "1"2) "2"3) "4"4) "5"127.0.0.1:6379> sismember set2 c(integer) 1
    2. 获取集合里面的元素个数、

      #scard key127.0.0.1:6379> scard set1(integer) 4
    3. 删除集合中的元素

      #srem key value127.0.0.1:6379> srem set1 1(integer) 1127.0.0.1:6379> smembers set11) "2"2) "4"3) "5"
    4. 随机返回集合一个或多个随机数

      #srandmember key count
    5. 随机弹出(出栈)

      #spop key
    6. 将key1的某个值赋值给key2

      smove key1 (的key值赋值给) key2 的某个值127.0.0.1:6379> smove set1 set2 3(integer) 1
    7. set集合例子(交集sinter 并集sunion 差集 sdiff

      127.0.0.1:6379> sadd set1 1 2 3 4 5(integer) 5127.0.0.1:6379> sadd set2 a b c 1 2(integer) 5

      交集

      127.0.0.1:6379> sinter set1 set21) "1"2) "2"

      并集

      127.0.0.1:6379> sunion set1 set21) "4"2) "a"3) "3"4) "b"5) "c"6) "1"7) "5"8) "2"

      差集

      127.0.0.1:6379> sdiff set1 set21) "3"2) "4"3) "5"
  • Zset类型

    有序集合、有序集合保留了集合不能重复的特征,还对存储的元素进行排序,他给每一个元素设置了score(分数),作为排序的依据

    有序集合中的元素不可以重复,但是score分数可以重复

    Eg:一个班里的同学学号不能重复,但考试成绩可以相同

    应用场景:

    ​ 在线统计积分排名,当玩家的分数发生变化,可以执行zadd方法更新玩家的分数,在Set基础上加一个score值,之前set是k1 v1 ,k2 v2 ,现在变成 k1 score1 v1 ; k2 score2 v2

    常用方法;

    1. 添加,查询,更新,删除
    #添加127.0.0.1:6379> zadd score 60 d 70 c 80 b 90 a(integer) 4#查询127.0.0.1:6379> zrange score 0 -11) "d"2) "c"3) "b"4) "a"#查询分数和值127.0.0.1:6379> zrange score 0 -1 withscores1) "d"2) "60"3) "c"4) "70"5) "b"6) "80"7) "a"8) "90"#更新#删除127.0.0.1:6379> zrem score d(integer) 1#获取成员对应键值索引127.0.0.1:6379> zrank score a(integer) 2#获取成员对应分值127.0.0.1:6379> zscore score a"90"
    1. 根据分值查询分值区间(从低到高排序)
    127.0.0.1:6379> zrangebyscore score 80 85 withscores1) "b"2) "80"
    1. 根据倒序查询分值(从高到低排序)
    127.0.0.1:6379> zrevrangebyscore score 90 65 withscores1) "a"2) "90"3) "b"4) "80"5) "c"6) "70"
    1. 给指定的分数增加或减去member值
    127.0.0.1:6379> zincrby score 10 a"100"
    结构类型 结构存储 读写
    String 字符串,整数,浮点,图片 对字符串进行操作,对整数或浮点数进行自增或自减操作
    List列表 双端链表,链表上的每一个节点都包含一个字符串 从链表的两端进行(lpush,rpush)push和(lpop,rpop)pop操作
    Hash(散列) 包含键值对的无序列表 添加,获取删除单个元素,获取所有键值对元素
    Set(无序集合) 包含无序不可重复的字符串 添加,获取删除单个元素,检查一个元素是否存在,交集,并集,差集
    ZSet(有序集合) 包含有序不可重复的元素,元素的排列顺序由分数值大小决定 添加,获取删除单个元素,根据分数范围或者成员获取元素
基本命令fushdb 清空当前数据库fushall 清空所有数据库exists  key 判断key值是否存在append追加字符串  如果字符串不存在相当于新建字符串截取字符串长度Strlen key * 获取所有key值set key 0 赋值0incr key值相当加一decr key值减一incrby  key 10 设定自动步长指定增量decrby key 10 减10设定自动步长指定减量rangegetrange key 0 3 截取字符串0到3的字符[0-3]getrange key 0 -1 截取全部字符串替换abcdefgsetrange key 1 xx 变成axxdefg 替换指定的字符串setex set with expire 设置过期时间 setnx set if not exist 不存在再设置 再分布式锁常常使用 如果不存在key 就设置成功,但如果存在就设置不成功ttl key 查看过期时间mset 批量设置值 mset k1 v1 k2 v2 k3 v3 同时设置多个值mget 批量取值 mset k1  k2  k3 msetnx 如果存在就设置失败,不存在就设置成功 原子性操作,全部成功才能成功,有一个失败就失败user:{
id}:{
field}set user:1 {
name:value,age:value} 设置user:1对象JSOn格式mset user:1:name value user:1:age value 同时设置多个属性getset 先get 后setgetset key value 如果key没有值就返回get为null但set为value值下一次get就是这个值 ,如果存在值就获取值并设置新值cas 比较并交换
window静默运行redis服务

在redis安装目录新建 redis.bat

@echo offredis-server.exe

再新建 redis.vbe

set ws=wscript.createobject("wscript.shell")ws.run "redis.bat /start",0

双击 redis.vbe 文件,redis服务就已经在后台安安静静地提供服务了。虽然双击后没有交互响应,但可以在任务管理器中查看

redis:    host: 127.0.0.1 #服务器地址    port: 6379 #默认端口号    password: 123456 #连接密码默认密码为空    lettuce:      pool:        max-active: 8 #连接池最大连接数(使用负数表示没有限制默认为8)        #max-wait: -1 #连接池最大阻塞等待时间(使用负数表示没有限制,默认-1)        max-idle: 8 #连接池中最大空闲连接默认为8        min-idle: 0 #连接池中最小空闲连接默认为0        #最大连接池:这个连接池能占有的最大数据库连接--->当前连接池占有的最小jdbc的连接(数据库连接)        #最小连接池:连接池一直保持的jdbc的连接-->数据库连接        #jdbc连接就是数据库连接
service接口上用注解
/**     * @Caching是:@Cacheable,@Cacheput,@CacheEvict注解的组合     * 其拥有三个属性cacheable,put,evict     * 分别用于指定@Cacheable,@Cacheput,@CacheEvict注解     * 作用:     *      当使用指定名字查询数据库后数据保存到缓存     *      只要是对应的属性id username age 就会直接查询缓存,而不是查询数据库     *     *       1.缓存击穿  大量并发访问同时查询正好缓存过期的数据     *       2.缓存雪崩 大量key同时过期 会引发     *       3.缓存穿透  查询空值(查询空数据)会引发     * @param id     * @return     */    @Caching(            //key可以使用Spring表达式语言(SqEL)来指定            /**             * methodName --->key="#root.methodName"methodName方法名 root当前对象             * 当前被调用的方法             * target --->key="#root.target" 当前被调用的目标对象             * targetClass ---->key="#root.targetClass" 当前被调用的目标对象类             * "#a0","#root.p0" 方法参数的名字 0 表示参数的索引             * result --> 方法执行后的返回值(判断后有效)             * key="#id"  ===  key="#p0"            */            cacheable = {
@Cacheable(value = "cacheDemo",key = "#result+'dataMap'")}, put ={
@CachePut(value = "cacheDemo",key = "#result.id")} ) Emp findEmpById(Integer id);
CacheTest类
@Componentpublic class DataCache {
private Map
dataMap = new HashMap<>(); //初始化数据 @PostConstruct public void init(){
dataMap.put(1L,"广州"); dataMap.put(2L,"深圳"); dataMap.put(3L,"上海"); dataMap.put(4L,"北京"); dataMap.put(5L,"河北"); } /** * 查询,如果数据没有在缓存那么就从DataMap中取,并将数据缓存,并将缓存的数据存储 * ,如果缓存了 *@Cacheable 属性: * value:指定缓存组件的名字 * key:缓存数据使用的key 默认使用方法中的key 可以用他来指定 * keyGenerator:作用与key一样 ,二选一 * cacheManager :缓存管理器 * cacheResolver :缓存解析器(反序列化) * condition :用于指定缓存条件 ,condition = "#id>3" id值大于三才缓存 * unless 否定缓存 当unless为true不缓存 * sync 是否使用异步模式 * @param id * @return */ @Cacheable(value = "cacheDemo",key = "#id+'_dataMap'")//cacheDemo::1dataMap(key值) value根据key值查找 public String query(Long id){
System.out.println("当前时间"+DateUtil.now()+"查询query ID 的值"+id); return dataMap.get(id); } /** * 更新 * 更新值到数据库,并且缓存更新,缓存中的存储的值 * @CachePut注解作用:主要针对方法配置能够根据方法的请求参数对其结果 * 进行缓存简单来说就是用户更新缓存数据 * 注意点: * 更新操作注解中的key和value必须与要更新缓存相同(保持一致) * value = "cacheDemo",key = "#id+'_dataMap'"这个要与查询@Cacheable中的那些名字相同 * CachePut要和Cacheable一致 */ @CachePut(value = "cacheDemo",key = "#id+'_dataMap'") public String put(Long id,String value){
System.out.println("当前时间"+DateUtil.now()+"更新 ID 的值"+id); dataMap.put(id,value); return value; } /** * 删除dataMap里面的数据,并且删除缓存cacheDemo的数据 * allEntries = true 删除所有缓存中的数据 * @CacheEvict清除缓存,删除数据库 * key:指定要清除缓存中的某条数据 * allEntries = true :删除所有缓存中的数据 * ,beforeInvocation = true 在方法执行之前清除缓存 * ,beforeInvocation = false 在方法执行之后清除缓存 * beforeInvocation = true 再方法之前使用的好处 * 如果方法出现异常缓存依旧会删除 */ @CacheEvict(value = "cacheDemo",key = "#id+'_dataMap'") public void remove(Long id){
dataMap.remove(id); }}

Spring Data Redis

Spring -data-redis 是spring-data模块的一部分用来支持spring管理项目对redis的操作,使用Java操作redis 最常用的多jedis,但并不是只有jedis,还是jdbc-redis这些都是redis的Java客户端

Spring-data-redis 提供了客户端的抽象,在开发中可以忽略具体的客户端的操作带来的影响,其本身就是spring生态的一部分,比起jedis更加方便

特征:

  • 自动管理连接池
  • 提供了一个高度封装RedisTemplate类
  • 针对Jedis客户端的大量Api进行归类封装、把同一类型操作封装成Operation接口,支持Redis中的五种数据类型 String ,List,Hash,Set(),zSet,针对数据序列化和反序列化,提供了多种可以选择的策略(RedisSerializable)接口
    • JdkSerializationRedisSerializer //存储java对象
    • StringRedisSerializer //字符串
    • Jackson2JsonRedisSerializer //将对象序列化成JSON格式存储在Redis中,需要Jackson.json.jar的支持
  • 在这个Spring-data-redis 中封装了对标redis中五种数据类型操作的方法StringRedisSerializer 中 的五种类型
    • opsForValue:对应String(字符串)
    • opsForZset::对应有序集合
    • opsForHash:对应哈希表hash
    • opsForList:对应list(列表)
    • opsForSet:对应无序集合
数据序列化(序列的目的是方便跨平台)

程序中数据的传输是以字节方式进行,所以数据读写操作必须要序列化操作

  1. 序列化:把对象转化为可传输的字节序列过程(存数据)
  2. 反序列化:把字节序列还原为对象的过程(取数据)

在Java中一切皆对象,而将对象的状态信息转化为存储的形式需要序列化

SpringRedisTemplate和RedisTemplate的区别
/** * 操作String类型 他们不共通 StringRedisTemplate是Spring-Data redis相对于jedisApi的高度封装 * */@Resourceprivate StringRedisTemplate stringRedisTemplate;/** * 操作任何类型 * 两者区别: *      1. RedisTemplate使用的是JDK序列化 *      其存储数据会先序列化成字节数组然后再存入Redis中 * *      2. StringRedisTemplate使用的是StringRedisSerializer *      当Redis中存储是字符串数据就实现StringRedisTemplate *      复杂的结构的对象类型数据使用RedisTemplate更好 */@Resourceprivate RedisTemplate
redisTemplate;@Testpublic void stringRedisTemplate(){
//设置key过期时间给指定的键设置过期时间 //stringRedisTemplate.expire("class1902",12, TimeUnit.SECONDS); //stringRedisTemplate.delete("class1902");删除指定的键 //stringRedisTemplate.hasKey("class1902");判断键是否存在 //stringRedisTemplate.getExpire("class1902");获取key的过期时间 //stringRedisTemplate.getExpire("class1902",TimeUnit.SECONDS);//获取指定格式key的过期时间 //stringRedisTemplate.rename("class1902","newClass1902");//修改key名旧换新 如果没有key值就会报错 //stringRedisTemplate.renameIfAbsent("class1902","newClass1903"); //stringRedisTemplate.type("class1902"); //stringRedisTemplate.move("class1902",2);//将指定key移动到指定库中 //stringRedisTemplate.randomKey();//用于抽奖 //stringRedisTemplate.persist("class1902");//持久化操作将key设置永久保存 //stringRedisTemplate.opsForValue().set("class1902","Redis"); Map
map = new HashMap<>(); map.put("k1","v1"); map.put("k2","v2"); map.put("k3","梁兴达"); stringRedisTemplate.opsForValue().multiSet(map);//存储map集合 //stringRedisTemplate.opsForValue().size();//获取key长度}

重写序列化方法以JSON格式

@Configuration//表示当前类属于配置类@EnableCaching//表示支持缓存注解/** * 配置springCacheManager 需要继承CachingConfigurerSupport * 重写CacheManager方法 * 在此之前确保容器中有RedisTemplate模板 * */public class RedisConfig extends CachingConfigurerSupport {
/** * 自定义key生成策略 * 策略:包名+类名+参数 * @return */ @Bean public KeyGenerator keyGenerator() {
return ((target,method,params) -> {
StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()).append("."); sb.append(method.getName()).append(Arrays.toString(params)); return sb.toString(); }); } /** * 默认情况下redisTemplate模板使用的是jdk方式进行序列化操作,不是很方便,所有需要重写序列化的实现 * 为什么需要序列化? * 你要记住一句话,在JAVA中,一切皆对象,而将对象的状态信息转为存储或传输的形式需要序列化。 * Spring Boot 在 RedisAutoConfiguration 中默认配置了 RedisTemplate
、 * StringRedisTemplate两个模板类,然而RedisTemplate
并未指定key、value的序列化器。 * Jackson2JsonRedisSerializer的序列化器需要引入Jackson的依赖 * * RedisSerializer redis序列化的接口类 * OxmSerializer xml到object的序列化/反序列化 * StringRedisSerializer string字符串的序列化/反序列化 * JacksonJsonRedisSerializer json到object的序列化/反序列化 * Jackson2JsonRedisSerializer json到object的序列化/反序列化 * JdkSerializationRedisSerializer java对象的序列化/反序列化 * * RedisTemplate默认使用的是JdkSerializationRedisSerializer * * JdkSerializationRedisSerializer:JDK自带的序列化方式、存储的字符串内容在序列化的情况下偏长,会占用过多的内存 * OxmSerializer:序列化的时间相对较长 * Jackson2JsonRedisSerializer:json数据格式、序列化时间和序列化之后内容的长度都要优于前两种 */ @Bean public RedisTemplate
redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate
redisTemplate = new RedisTemplate<>(); //构造实例 redisTemplate.setConnectionFactory(redisConnectionFactory); //设置序列化操作 Jackson2JsonRedisSerializer
jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); //序列化时将对象全类名一起保存下来 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); //字符串类型的序列化操作 RedisSerializer
stringSerializer = new StringRedisSerializer(); //序列化String类型的key值 redisTemplate.setKeySerializer(stringSerializer); //序列化JSON格式的值value redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); //散列Hash的序列化 redisTemplate.setHashKeySerializer(stringSerializer);//key值序列化 redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);//value序列化 //加载一下 redisTemplate.afterPropertiesSet(); return redisTemplate; } //配置 cacheManager 代替默认的cacheManager (缓存管理器) //JdkSerializationRedisSerializer:JDK自带的序列化方式、存储的字符串内容在序列化的情况下偏长,会占用过多的内存 //配置 cacheManager 代替默认的cacheManager (缓存管理器) /** *CacheManager是对Cache进行管理、创建、获取、销毁等操作的,在创建Cache时,需要对其进行序列化。 * 在重写cacheManager时,通过RedisCacheConfiguration 对缓存数据的key、value进行序列化操作 * key对应String格式 * value对应JSON格式,其目的也是为了解决缓存中中文乱码问题 * @param redisTemplate * @return */ @Bean public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); //key的序列化操作,解决中文乱码问题 redisCacheConfiguration.serializeKeysWith( RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getKeySerializer())); //配置管理器的JSON序列化器 redisCacheConfiguration.serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer())) .disableCachingNullValues()//不缓存空值 .entryTtl(Duration.ofMillis(60));//默认缓存过期时间 //设置序列化管理器.使用自定义的配置构建缓存管理器 RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisTemplate.getConnectionFactory()).cacheDefaults(redisCacheConfiguration).build(); return redisCacheManager; }}

RedisService

比较重要认真看

package com.liang.service.redis;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.util.CollectionUtils;import javax.annotation.Resource;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.TimeUnit;/** * @ClassName RedisService * @Description: TODO * @Author hefeng * @Date 11:56 PM 1/7/22 * @Version V1.0 * 基于spring和redis的redisTemplate工具类 * 针对所有的hash 都是以h开头的方法 * 针对所有的Set 都是以s开头的方法 * 针对所有的List 都是以l开头的方法 **/public class RedisService {
@Resource private RedisTemplate redisTemplate; /** * 指定缓存失效时间 * @param key 键 * @param time 时间(秒) * @return */ public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 根据key 获取过期时间 * * @param key 键 不能为null * @return 时间(秒) 返回0代表为永久有效 */ public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 判断key是否存在 * * @param key 键 * @return true 存在 false不存在 */ public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key); } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 删除缓存 * * @param key 可以传一个值 或多个 */ @SuppressWarnings("unchecked") public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]); } else {
redisTemplate.delete(CollectionUtils.arrayToList(key)); } } } //============================String============================= /** * 普通缓存获取 * * @param key 键 * @return 值 */ public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存放入 * * @param key 键 * @param value 值 * @return true成功 false失败 */ public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 普通缓存放入并设置时间 * * @param key 键 * @param value 值 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else {
set(key, value); } return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 递增 * * @param key 键 * @param delta(大于0) * @return */ public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 递减 * * @param key 键 * @param delta 要减少几(小于0) * @return */ public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0"); } return redisTemplate.opsForValue().increment(key, -delta); } //================================Map================================= /** * HashGet * * @param key 键 不能为null * @param item 项 不能为null * @return 值 */ public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item); } /** * 获取hashKey对应的所有键值 * * @param key 键 * @return 对应的多个键值 */ public Map
hmget(String key) {
return redisTemplate.opsForHash().entries(key); } /** * HashSet * * @param key 键 * @param map 对应多个键值 * @return true 成功 false 失败 */ public boolean hmset(String key, Map
map) {
try {
redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * HashSet 并设置时间 * * @param key 键 * @param map 对应多个键值 * @param time 时间(秒) * @return true成功 false失败 */ public boolean hmset(String key, Map
map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map); if (time > 0) {
expire(key, time); } return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * * @param key 键 * @param item 项 * @param value 值 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * * @param key 键 * @param item 项 * @param value 值 * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value); if (time > 0) {
expire(key, time); } return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 删除hash表中的值 * * @param key 键 不能为null * @param item 项 可以使多个 不能为null */ public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item); } /** * 判断hash表中是否有该项的值 * * @param key 键 不能为null * @param item 项 不能为null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item); } /** * hash递增 如果不存在,就会创建一个 并把新增后的值返回 * * @param key 键 * @param item 项 * @param by 要增加几(大于0) * @return */ public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by); } /** * hash递减 * * @param key 键 * @param item 项 * @param by 要减少记(小于0) * @return */ public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by); } //============================set============================= /** * 根据key获取Set中的所有值 * * @param key 键 * @return */ public Set
sGet(String key) {
try {
return redisTemplate.opsForSet().members(key); } catch (Exception e) {
e.printStackTrace(); return null; } } /** * 根据value从一个set中查询,是否存在 * * @param key 键 * @param value 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 将数据放入set缓存 * * @param key 键 * @param values 值 可以是多个 * @return 成功个数 */ public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values); } catch (Exception e) {
e.printStackTrace(); return 0; } } /** * 将set数据放入缓存 * * @param key 键 * @param time 时间(秒) * @param values 值 可以是多个 * @return 成功个数 */ public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) expire(key, time); return count; } catch (Exception e) {
e.printStackTrace(); return 0; } } /** * 获取set缓存的长度 * * @param key 键 * @return */ public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key); } catch (Exception e) {
e.printStackTrace(); return 0; } } /** * 移除值为value的 * * @param key 键 * @param values 值 可以是多个 * @return 移除的个数 */ public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values); return count; } catch (Exception e) {
e.printStackTrace(); return 0; } } //===============================list================================= /** * 获取list缓存的内容 * * @param key 键 * @param start 开始 * @param end 结束 0 到 -1代表所有值 * @return */ public List lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) {
e.printStackTrace(); return null; } } /** * 获取list缓存的长度 * * @param key 键 * @return */ public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key); } catch (Exception e) {
e.printStackTrace(); return 0; } } /** * 通过索引 获取list中的值 * * @param key 键 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 * @return */ public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index); } catch (Exception e) {
e.printStackTrace(); return null; } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @return */ public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) {
e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @return */ public boolean lSet(String key, List value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, List value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据索引修改list中的某条数据 * * @param key 键 * @param index 索引 * @param value 值 * @return */ public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 移除N个值为value * * @param key 键 * @param count 移除多少个 * @param value 值 * @return 移除的个数 */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); return remove; } catch (Exception e) { e.printStackTrace(); return 0; } }}

session共享

分布式项目,微服务中,session共享是最基本的要求,一般将session托管到redis中是最常用的解决方案

SpringSession,器提供了一套创建和管理HttpSession的方案,提供集群的功能,默认采用外置的redis来存储session数据,以此来解决session共享问题

依赖:

org.springframework.session
spring-session-data-redis
生成日期20220108DD00001订单号
/**     * Redis计数器     * 需求:在实际开发过程中产品组给定的需求,有规律的订单号     * Eg:     *  订单号格式:20220108DD00001  第二个:20220108DD00002     *  明天的订单:20220109DD00001  第二个:20220109DD00002     */    public String getOrderCode(String type){
Date date = new Date(); String format = DateUtil.format(date, "yyyyMMdd"); Long incr = redisService.incr(type + format, 1L); String orderCode = padRight(incr.toString(), 7, "0"); return format+type+orderCode; } /** * 右补位 左对齐 * * @param orderStr 原字符串 * @param len 目标字符串位数 * @param ale 补位字符 * @return */ public String padRight(String orderStr,int len ,String ale){
String str = ""; int strLength = orderStr.length(); if (strLength

调用工具类

/**     * 递增     *     * @param key        键     * @param delta(大于0)     * @return     */    public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); }

转载地址:https://blog.csdn.net/m0_46177001/article/details/126018197 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:redis笔记
下一篇:Redis笔记

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年03月03日 07时26分47秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

java 监控 宕机_JAVA监测tomcat是否宕机,控制重启 2019-04-21
catch that cow java_POJ3278——Catch That Cow 2019-04-21
java integer 不变模式_Java代码的变与不变 2019-04-21
java guava 使用_Java8-Guava实战示例 2019-04-21
python barrier option pricing_《Python金融数据分析》书内代码实战与讲解(二)金融衍生物定价... 2019-04-21
java自带工具_深入了解Java JDK自带工具,包括javac、jar、jstack等,实用~ 2019-04-21
gnome mysql client_解决MySQLWorkbenchgnome-keyring-daemon错误的方法分享 2019-04-21
java线程占用CPU_在windows下揪出java程序占用cpu很高的线程并完美解决 2019-04-21
java多态替换switch_使多态性无法解决那些switch / case语句的麻烦 2019-04-21
java httpclient 进度条_如何使用Apache HttpClient 4获取文件上传的进度条? 2019-04-21
下列不属于java语言特点的是_下列选项中,不属于Java语言特点的一项是( )。... 2019-04-21
java中小数的乘法_javascript的小数点乘法除法实例 2019-04-21
kappa一致性检验教程_SPSS在线_SPSSAU_Kappa一致性检验 2019-04-21
linux shell mysql备份_linux shell 备份mysql 数据库 2019-04-21
Java双向链表时间复杂度_链表是什么?有多少种链表?时间复杂度是? 2019-04-21
unity3d能和java系统整合吗_Android与Unity3d的整合 2019-04-21
minecraft666java_我的世界的666的世界 2019-04-21
辽宁师范大学java_辽宁师范大学心理学院 2019-04-21
java程序有连接数据库_Java程序连接数据库 2019-04-21
java reduce.mdn_reduce高级用法 2019-04-21