1、redis功能:数据库、缓存、消息队列
2、常用类型与命令:
- String类型:
key 是否存在:exists key
key 移动到指定库:move key 1
key 移除:del key
设置过期时间(s):expire name 10
剩余过期时间(s):ttl key
查看key的类型:type key
追加字符串,key不存在set:append key str
自增:incr key
自减:decr key
步长:incrby/decrby key step
字符串截取:getrange key begin end
获取全部字符串:getrange key 0 -1
字符串替换:setrange key begin end
设置过期时间(set with expire):setex key second value
不存在再设置,分布式锁经常使用(set if not expire):setnx key value
批量创建:mset k1 v1 k2 v2 k3 v3
批量获取:mget k1 k2 k3
不存在再创建(一起成功或失败):msetnx k1 v1 k4 v4
设置对象:mset user:1:name zhangsan user:2:age 2
先get再set:getset key value
- list类型:双头链表(栈:lpush lpop 队列:lpush rpop)
左插入:lpush list value
右插入:rpush list value
左截取:lrange list start end
右截取:rrange list start end
从左取出前num个:lpop list num
从右取出前num个:rpop list num
获取list长度:llen list
移除list中指定的value item:lrem list 1 value
通过下标截取指定长度,list已修改,只剩下截取的:ltrim list start end
移除list最右边的元素并添加到新的list的左边:rpoplpush oldList newList
设置list指定下标的值(不存在,报错,存在更新):lset list num item
向某个指定value前或后插入值:insert list before/after oldvalue newvalue
- set类型(无序,不能重复):
向集合添加值:sadd set hello
查出集合内所有元素:smembers set
判断集合中是否存在某个值(1:存在0:不存在):sismember set item
获取集合中元素的个数:scard set
获取集合内的指定个数的随机元素:srandmember set num
oleset中的item移动到newset:smove oleset newset item
随机删除set中的num个元素:spop set num
数字集合类-差集(set1-set2):sdiff set1 set2
数字集合类-交集:sinter set1 set2
数字集合类-并集:sunion set1 set2
- hash类型:
向hash设置元素:hset/hmset hash key1 value1 key2 value2
找到hash中指定key的value(hset:单个):hset/hmget hash key
获取hash中所有的数据:hgetall hash
删除hash中指定的key-value:hdel hash key
获取hsah的key-value个数:hlen hash
判断hash中指定key是否存在:hexists hash key
获取所有key:hkeys hash
获取所有value:hvals hash
自增(没有hdecrby,step可为负):hincr(by) hash key (step)
不存在key就添加(存在不能设置):hsetnx hash key value
- Zset类型(有序集合,按key排序):
添加元素:zadd zset key value key2 value
集合排序(倒序):zrevrange zset min(max) max(min)
集合排序(正序):zrangebyscore zset -inf(min) +inf(max)
集合排序(将序):zrevrangebyscore zset +inf(max) -inf(min)
获取集合所有元素:zrange zset 0 -1
移除集合中元素:zrem zset value
获取有序集合中指定区间内的元素个数(闭区间):zcount zset begin end
- geospatial地理位置(底层zset):key-value(经度、维度、城市)
添加地理位置(两极无法添加):geoadd key 116.40 39.90 beijing
获取指定城市的经纬度:geopos key beijing
获取两个指定位置的经纬度(m/km):geodist key beijing shanghai km
以给定的经纬度为中心,找出某一半径的元素(110 30:经纬度 radius:半径):georadius key 110 30 radius km
以给定元素经纬度为中心,找出某一半径的元素:georadiusbymember key beijing redius km
将经纬度转换为字符串,字符串越接近,则距离越近:geohash key beijing chongqing
查看地图中所有key:zrange key 0 -1
删除地图中指定的元素:zrem key beijing
- Hyperloglog数据结构:基数(集合中不重复的元素)统计的算法(错误率0.81%)
添加元素:pfadd key item1 item2 item3
集合合并(并集):pfmerge newkey oldkey1 oldkey2
统计集合内不重复的元素数量:pfcount key
应用:统计网页Uv - bitmap位图(按位存储):
添加:setbit key 0(0-7) 1(0/1)
获取:getbit key 0(0-7)
统计1的个数:bitcount key
3、事务:
- mysql事务原则:ACID原子性、一致性、隔离性、持久性
- redis事务原则:redis单条命令保证原子性,但事务不保证原子性
- redis事务本质:一组命令的集合,事务中的所有命令都会序列化,事务执行过程中,会按顺序执行。一致性、顺序性、排他性、
- redis事务:
开启事务(multi)
命令入队(...)
执行事务(exec)
- 放弃事务:
取消事务(discard)
- 事务异常:
编译异常(执行事务报错,所有命令不执行)
运行异常(错误的命令报错后,会往下正常执行其他命令)
- 监控:watch实现乐观锁
悲观锁:认为无论干什么都加锁,处理完再解锁
乐观锁:认为无论干什么都不加锁,更新时判断是否被修改过
使用:开启事务,执行时,若key数据期间未变动,正常执行成功。若事务执行中,key数据变动,执行失败,解锁,后再加监视、执行事务。
a.监视key(watch key)
b.开启事务(multi)
c....
d.执行事务(exec)
e.取消监视(解锁)(unwatch)
*重复a.b.c.d.步骤*
4、jedis:redis官方推荐的java连接开发工具、操作中间件
引入配置
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-autoconfigure -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
连接:
Jedis jedis = new Jedis("127.0.0.1",6379);
JSONObject jsonObject = new JSONObject();
jsonObject.put("name","zhangsan");
jsonObject.put("age",12);
String result = jsonObject.toJSONString();
//jedis.set("user1","111");
//jedis.watch(user1);
Transaction multi = jedis.multi();
try{
multi.set("user1",result );
multi.set("user2",result );
multi.exec();
}catch(Exception e){
//jedis.unwatch();
multi.discardd();
e.printStackTrace();
}finally{
jedis.close();
}
5、springBoot整合
在springBoot2.x后,jedis被替换了lettuce
jedis:直连,多线程不安全,要避免,需用连接池;BIO模式
lettuce:采用netty,实例多线程共享,线程安全;NIO模式
PS:BIO模式(同步且阻塞)、NIO模式(同步非阻塞)、AIO(异步非阻塞)
导入依赖:Nosql-Spring Data Redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置连接:
spring.redis.host=127.0.0.1
spring.redis.port=6379
上手使用:可以通过自定义一个redisTemplate来替换默认的;
默认的RedisTemplate没有过多的设置,redis对象都需要序列化;
redisTemplate两个范型都是<Object,Object>的,使用需要强制转换成<String,Object>的;
默认的序列化方式是JDK序列化,会让字符串转义,在企业中,所有pojo都会用json序列化
//配置类
@Configuration
public class RedisConfig{
//编写自己的RedisTemplate配置
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
//为开发方便,使用<String,Object>序列化
RedisTemplate<String, Object> template = new RedisTemplate<String,Object>();
template.setConnectionFactory(redisConnectionFactory);
//序列化配置
//json序列化
Jackson2JsonRedisSerializer<Object> JsonRedisSerializer=new Jackson2JsonRedisSerializer<Object.class>;
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.All,JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
JsonRedisSerializer.setObjectMapper(om)
//String序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String方式序列化
template.setKeySerializer(StringRedisSerializer);
//hash的key也采用Striing的序列化方式
template.setHashKeySerializer(StringRedisSerializer);
//value的序列化方式采用jackson
template.setValueSerializer(JsonRedisSerializer);
//hash的value的序列化方式采用jackson
template.setHashValueSerializer(JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
//注入
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate redisTemplate;
//使用
//redisTemplate.opsForValue(操作字符串,类似String)
//redisTemplate.opsForList(list)
//redisTemplate.opsForSet(set)
//redisTemplate.opsForHash(hash)
//redisTemplate.opsForZSet(zset)
//redisTemplate.opsForGeo(geo)
//redisTemplate.opsForHyperLogLog(heperloglog)
//除了基本的操作,常用的方法都可直接通过redisTemplate进行操作,比如事务和基本的CRUD
//获取redis连接对象
//RedisConnection connection =redisTemplate.getConnectionFactory().getConnection();
//清除当前数据库,慎用,尽量不用
//connection.flushdb();
redisTemplate.opsForValue.set("name","zhangsan")
log.info(redisTemplate.opsForValue.get("name"));
6、配置
``bind 127.0.0.1 //绑定ip 远程访问*
protected-mode yes //保护模式
port 6379 //端口
daemonize yes//守护进程方式(后台方式)运行,默认是no,改为yes
pidfile /var/run/redis_6379.pid //以后台方式运行需指定pid文件
loglevel notice //日志级别
logfile //日志文件位置
datebase 16//数据库数量,默认16
always-show-logo//是否显示logo
save time keyNum//如果在time(s)内至少有keyNum个key进行了修改,就持久化到文件.rdb.aof
stop-writes-on-bgsave-error yes //持久化失败后,是否继续运行
rdbcompression yes //是否压缩rdb文件
rdbchecksum yes //保存rdb文件,是否检查错误
dir ./ //rdb文件位置
requirepass password //设置redis密码
maxcleants 100000//redis客户端最大连接数
maxmemory //redis最大内存
maxmemory-policy noeviction //内存达上限处理策略
volatile-lru//只对设置了过期时间的key进行lru(移除)
allkeys-lru//删除lru算法的key
volatile-random//随机删除即将过期的key
allkeys-random//随机删除
volatile-ttl//删除即将过期的
noeviction//永不过期,返回错误
appendonly no//默认不开启aof模式,默认使用rdb
appendfilename “appendonly.aof”//持久化文件名
appendfsync no //不执行同步,系统同步数据,速度快
always//每次修改都会同步,消耗性能,速度慢
everysec//默认项
每秒执行同步,可能会丢失这1s的数据
``
7、持久化
RDB:
redis是内存数据库,如果不将内存的数据保存到磁盘,服务器进程停止,服务器中的redis数据库的状态也会丢失,需要持久化来解决这个问题。
工作原理:redis单独创建一个子进程,在指定时间间隔内,将内存中的数据写入磁盘覆盖之前的snapshot快照文件(dump.rdb
),恢复时将快照文件读到内存。
缺点:rdb持久化最后一次的数据可能会丢失
触发机制:
save的规则满足,触发
退出redis,触发
flushall(别用
),触发
恢复rdb文件:
将rdb文件放入redis启动目录,redis启动会自动检查
查询需要存放的地方:
获取目录:config get dir
优点:
适合大规模数据恢复
对数据完整性要求不高
缺点:
要一定的间隔时间
AOF:
将所有命令记录下来,恢复时把记录文件(appendonly.aof
)全部执行一遍。
以日志形式记录redis执行过的每个操作(读操作不记录), 只追加操作记录,redis启动会读取改文件来重新执行命令构建数据。默认不开启 appendonly no/yes,修改重启(生成appendonly.aof文件)生效
同时开启AOF、RDB,优先使用AOF
如果AOF文件有错,redis启动不了,需要用`rerdis-check-aof --fix filename`进行修复后,在进行修复
重写规则:默认aof文件大于64M,开启新的子进程写入新AOF文件
优点:
每次修改都同步,文件完整性优
每秒同步,可能丢失1秒数据
从不同步,效率最高
缺点:
aof数据文件远大于rdb,修复数据比rdb慢
aof运行效率比rdb慢
redis发布订阅
订阅频道(没有会创建,返回内容 消息,频道,内容):subscribe channelName
发布频道消息(value:内容):publish channelName value