Redis随笔
Redis为非关系型数据库,相较于mysql数据库具体表现为如下:
结构化:关系型数据库结构化,如表。非关系型数据库没有。
关联性:关系型数据库数据之间有关联,非关系型数据库数据直接无关联。
查询方式:关系型采用sql语句,非关系型不使用。
事务特性:关系型数据库支持事务ACID,非关系型只能满足基本BASE。
存储方式:关系型存储磁盘,非关系型存储内存中。
场景:对数据安全性、一致性等要求较高用关系型数据库,对性能要求高用非关系型数据库。
Redis数据库特征
键值型:基于key/value,可支持多种数据类型。
单线程:命令具备原子性,虽然6.0后支持多线程,但核心的逻辑处理还是单线程。
低延迟,速度快:基于内存,IO多路复用,代码好。
支持数据持久化:定期写入磁盘,若出现断电可从磁盘写回,不会增加mysql压力。
支持主从集群、分片集群。
支持多语言客户端。
Redis安装
1.因为redis基于c语言编写,故要先有gcc依赖。
下载依赖
yum install -y gcc tcl
2.下载redis安装包,解压。
3.允许编译命令,将redis安装。
4.验证是否成功,执行命令redis-server(前台启动,若当前界面退出,redis停止)
后台运行redis
想redis运行后台,需要改其配置文件。
1.备份,先将原来redis.conf文件复制一份备份,防止后来需要使用。(cp redis.conf 新文件名)
2.配置redis.conf
//默认,只能本机访问,指定访问的ip
bind 127.0.0.1
//修改为任意ip,实际不推荐
bind 0.0.0.0//设置为守护进程,可后台运行
daemonize yes
//设置密码
requirepass 123321//其他
databases 库数量(默认16)
//设置redis日志文件,文件在运行redis的目录下
logfile 文件名
测试redis是否运行连通
命令:ping
结果:pong
Redis数据结构
redis是key/value的数据库,key通常为String,value类型多样,如String,List,Hash,Set等。
通用指令
*表示匹配任意字符,?表示匹配单个字符。
key *:查询所有key。
key a??:查询为a开头的字符长度为3的key。
set key value:创建数据。
mset k1 v1 k2 v2...:一次创建多个数据。
del key1 key2...:一次删除一个或多个数据,如果删除不存在数据,不影响删除其他数据。返回结果为删除的个数。
exists k1 k2...:查询一个或多个key是否存在,返回存在的数量。
expire key 有效期:给key设置有效期,时间单位为秒。(超时自动删除该数据)。
ttl key:查询key剩余有效期。
String类型
根据格式不同,可分3类:
string:普通字符串
int:整数类型,可以做自增,自减操作。
float:浮点型,也可以做自增、自减。
//添加,若存在该key则覆盖value
set key value
mset k1 v1 k2 v2...
//防止value覆盖,若k1存在,则不进行覆盖
setnx k1 v2
set k1 v2 nx
//上述未指定有效期,默认永久存在
//添加时设置有效期
setex k1 时间 v1
set k1 v1 ex 时间
//获取
get k1
mget k1 k2...
//自增,对于数字型字符串可以自增自减
incr k1
//指定自增大小
incrby k1 10
//自减
decr k1
decrby k1 10
//自增不支持浮点数
//使用如下让浮点数自增
incrbyfloat k1 10
key通常格式
[项目名]:[业务名]:[类型]:[id],如:project:user:1。避免数据量多情况下相互覆盖影响。
Hash类型
散列,是一个无序字典,类似HashMap,每个字段独立存储。
常用命令
增加 设置k1的属性field为value
hset k1 field value
获取
hget k1 field
一次性设置多个属性
hmset k1 name xiaoming age 18
一次性获取多个属性值
hget k1 name age
获取所有属性和属性值
hgetall k1如:name xiaoming age 10
获取所有属性
hkeys k1 结果:name age
获取所有属性值
hvals k1 结果:xiaoming 10
自增
hincrby k1 age 2 将age加2
设置k1未有该属性才添加
hsetnx k1 name fff 结果:添加不成功,因为name属性存在
List类型
双向链表,类似LinkedList。
特点:有序,元素可重复,插入和删除速度快,查询速度慢。
命令
添加多个元素,从左插入
lpush l1 1 2 3
从右插入多个元素
rpush l1 4 5 6 //l1:3 2 1 4 5 6
从左移除并返回2个元素
lpop l1 2 //3 2
从右
rpop l1 2 //6 5
获取范围数据 [l,r]从0开始
lrange l1 0 1 //1 4
获取l1头节点元素,在指定时间内等待,若有则返回,超时报错
blpop l1 时间
Set类型
与HashSet类似
特点:无序,元素不可重复,查找快,支持并集,交集等。
命令
添加一个或多个元素
sadd s1 a b c
删除元素
srem s1 a
统计s1中元素个数
scard s1 //为2
查询某元素是否在集合中
sismember s1 a
smembers s1 获取所有元素k1 : a b c
k2 : b c d获取两个集合交集
sinter k1 k2 结果:b c
获取差集
sdiff k1 k2 结果:a
获取两个集合并集
sunion k1 k2 结果:a b c d
SortedSet
有序的set
特点:有序,元素不可重复,查询快
命令
添加元素
zadd s1 分数 name 分数2 name2 ...
删除
zrem s1 name1 name2
查询name对应分数
zscore s1 name1
查询排名(默认升序,即排名从小到大,0为最小元素,想反序 将zrank 修改 zrevrank)
zrank s1 name1
统计s1的的元素个数
zcard s1
统计s1指定范围类元素个数
zcount s1 0 100
获取指定范围类元素
zrangebyscore s1 0 100
获取指定排名内的元素
zrang s1 0 1(获取1,2名)
指定元素分数自增
zincrby s1 increment 2
Redis客户端
Redis的Java客户端
Jedis:以Redis的命令作为方法名,能快速上手,但线程不安全,多线程需要基于线程池来使用。
lettuce:基于Netty实现,支持响应式编程,并且线程安全,支持Redis的哨兵等模式。
Spring中SpringDataRedis整合了以上两个。
基本步骤
// 创建Jedis对象并连接到Redis服务器,ip地址为localhost,端口为6379jedis = new Jedis("localhost", 6379);// 设置登录密码jedis.auth("123456");// 选择数据库jedis.select(0);//基本使用jedis.set("name", "TJ");String name = jedis.get("name");System.out.println("name: " + name);// 关闭Jedis连接if (jedis != null) {jedis.close();}
Jedis连接池
为了多线程下使用安全
public class JedisConnectionFactory {public static final JedisPool jedisPool;static {//创建JedisPoolConfig对象,配置连接池参数JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();//设置最大连接数jedisPoolConfig.setMaxTotal(10);//设置最大空闲连接数jedisPoolConfig.setMaxIdle(8);//设置最小空闲连接数jedisPoolConfig.setMinIdle(4);//设置连接超时时间,单位毫秒jedisPoolConfig.setMaxWaitMillis(10000);jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1",6379,1000,"123456");}public static Jedis getJedis() {//从连接池中获取Jedis实例return jedisPool.getResource();}
}
SpringDataRedis
是Spring中数据操作模块
特点:
提供对不同Redis客户端的整合(包括Lettuce和Jedis);
使用RedisTemplate操作Redis;
支持Redis订阅,各种哨兵等模式;
支持Lettuce响应式编程;
支持字符串等序列化和反序列化;
使用
首先RedisTemplate封装了不同的对象,这些对象是针对不同类型的操作对象。
快速入门
1.导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
2.配置文件(resource/application.yml)
spring:redis:host: 127.0.0.1port: 6379password: 123456lettuce:pool:max-active: 8max-idle: 8min-idle: 2max-wait: 1000ms
3.注入RedisTemplate
@Autowird private RedisTemplate redisTemplate;
4.使用
@Testvoid testString() {//opsForValue()方法获取操作字符串的对象redisTemplate.opsForValue().set("hello", "world");Object name = redisTemplate.opsForValue().get("hello");System.out.println("name: "+name);}
问题:使用时redis那边存入为二进制,导致不一致
解决:使用序列化
1.创建配置类
@Configuration
public class RedisConfig {public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){//创建rRedisTemplate对象RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();//设置链接工程redisTemplate.setConnectionFactory(redisConnectionFactory);//创建JSON序列化工具StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();//设置Key的序列化redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);//设置Value的序列号redisTemplate.setValueSerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(stringRedisSerializer);return redisTemplate;}
}
使用
@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Testvoid testString() {redisTemplate.opsForValue().set("hello", "world");Object name = redisTemplate.opsForValue().get("hello");System.out.println("name: "+name);}
上述方法中,为了反序列化知道元素类型,会将class类写入内存,占用部分空间。
ObjectMapper
我们可以手动序列号和反序列化节省内存空间占用。
通过ObjectMapper实现。
//创建 ObjectMapper 实例private static final ObjectMapper objectMapper = new ObjectMapper();void testDao(){//假如我们要将Dao存入redisDao dao = new Dao("xiao ming",23);//手动序列化String s = objectMapper.writeValueAsString(dao);//写入数据stringRedisTemplate.opsForValue().set("user:id:1",s);//获取数据String res = stringRedisTemplate.opsForValue().get("user:id:1");//手动反序列化Dao dao1 = objectMapper.readValue(res, Dao.class);System.out.println(dao1);}