Redis
Redis介绍
Redis是什么
redis是一种支持Key-Value等多种数据结构的存储系统。可用于缓存,事件发布或订阅,高速队列等场景。该数据库使用ANSI C语言编写,支持网络,提供字符串,哈希,列表,队列,集合结构直接存取,基于内存,可持久化。
Redis应用场景
会话缓存(最常用),消息队列,比如支付活动排行榜或计数发布,订阅消息(消息通知),商品列表,评论列表等
Redis支持的数据类型
redis一共支持五种数据类:string(字符串),hash(哈希),list(列表),set(集合)和zset(sorted set有序集合)。
redis常用命令
String
赋值 set key value
取值 get key
删除:del key
递增 :INCR key
减去指定量值后key的值: Decrby key num
应用场景:计数等
List
增加元素:LPUSH key value [value …] RPUSH key value [value …]
查看列表 LRANGE key start stop
从列表两端弹出元素:LPOP key RPOP key
获取列表中元素的个数:llen key
删除列表中的值:LREM key count value
Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如关注列表,粉丝列表等都可以用Redis的list结构来实现。
List 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用List结构,我们可以轻松地实现最新消息排行等功能。List的另一个应用就是消息队列,
可以利用List的PUSH操作,将任务存在List中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作List中某一段的api,你可以直接查询,删除List中某一段的元素。
实现方式:
Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。
Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素,这样List即可以作为栈,也可以作为队列。
Set
增加/删除元素: SADD key value [value …] Srem key value [value …]
弹出元素:spop key
获得集合中的所有元素:SMEMBERS key
set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
获取某段时间所有数据去重值
这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。
Zset
赋值: ZADD key score value [score value …]
删除:zrem key value
获取有序集合的成员数:ZCARD key
使用场景:
Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构。 和Set相比,Sorted Set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列,比如一个存储全班同学成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用Sorted Set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行
另一个很普遍的需求是各种数据库的数据并非存储在内存中,因此在按得分排序以及实时更新这些几乎每秒钟都需要更新的功能上数据库的性能不够理想。典型的比如那些在线游戏的排行榜,比如一个Facebook的游戏,根据得分你通常想要:
- 列出前100名高分选手
- 列出某用户当前的全球排名
这些操作对于Redis来说小菜一碟,即使你有几百万个用户,每分钟都会有几百万个新的得分。模式是这样的,每次获得新得分时,我们用这样的代码:
ZADD leaderboard
你可能用userID来取代username,这取决于你是怎么设计的。得到前100名高分用户很简单:
ZREVRANGE leaderboard 0 99
用户的全球排名也相似,只需要:
ZRANK leaderboard
。
Hash
赋值:hset key field value hmset key field value [field value……]
取值:hget key field hgetall key
删除:hdel key field ……
我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:
用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,
其他命令
切换数据库:select 1
查看数据库key的数量:dbsize
清空所有key:flushall
检查key是否存在:EXISTS key
为给定 key 设置过期时间,以秒计:EXPIRE key seconds
Java客户端使用Jedis连接redis操作数据
jar包
jar包如下:
单实例连接
通过创建单实例jedis对象连接redis服务,如下代码:
// 单实例连接redis
@org.junit.Test
public void test1(){
JedisPoolConfig config = new JedisPoolConfig();
//最大连接数
config.setMaxTotal(30);
//最大连接空闲数
config.setMaxIdle(2);
JedisPool pool = new JedisPool("localhost");//创建连接池
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.lpush("test", "a");
jedis.lpush("test", "b");
jedis.lpush("test", "c");
jedis.lpush("test", "d");
byte[] bytes = "test".getBytes();
//jedis.lrange(key, start, end)
Long llen = jedis.llen("test");
for (int i = 0; i <llen ; i++) {
System.out.println(jedis.lpop("test"));
}
}catch(Exception ex){
ex.printStackTrace();
}finally{
if(jedis != null){
//关闭连接
jedis.close();
}
}
}
使用连接池连接
通过单实例连接redis不能对redis连接进行共享,可以使用连接池对redis连接进行共享,提高资源利用率,使用jedisPool连接redis服务,如下代码:
@Test
public void pool() {
JedisPoolConfig config = new JedisPoolConfig();
//最大连接数
config.setMaxTotal(30);
//最大连接空闲数
config.setMaxIdle(2);
JedisPool pool = new JedisPool(config, "192.168.101.3", 6379);
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.set("name", "lisi");
String name = jedis.get("name");
System.out.println(name);
}catch(Exception ex){
ex.printStackTrace();
}finally{
if(jedis != null){
//关闭连接
jedis.close();
}
}
}
Redis持久化
RDB持久化配置
Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息.
save 900 1
save 300 10
save 60 10000
命令:save
Redis发布与订阅
订阅给定的一个或多个频道的信息:SUBSCRIBE channel [channel …]
订阅一个或多个符合给定模式的频道: Psubscribe
发布消息:publish channel message
应用场景:粉丝订阅关注等
Redis事务
Redis事务与mysql事务不一样,批量操作数据不会回滚, 单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做
Multi
Set key value
Set key1 value1
Set key2 value2
Exec
如果key1这条数据出错,key这条命令执行的数据不会回滚,key2这条命令也会继续执行
redis应用场景举例
-显示最新的n条消息
lpush message string
lpush message string1
LTRIM message 0- (n-1)
Redis内存设置
单位为字节,一般推荐Redis设置内存为最大物理内存的四分之三,所以设置3G,换成byte是3006477104
例子:maxmemory 3006477104#我的内存是4G 四分之三转换为字节
个人理解:
关于数据库的一致性和条件查询 当有用户进行数据的插入操作,不应该直接插入到redis缓存redis中缓存一些请求量比较大的数据,这些缓存数据,mysql中一定也是有的,没必要所有数据都缓存进去,直接插入到数据库,下次访问这条数据的时候,先从数据库里面查出数据,再将数据缓存到redis,redis中这条数据缓存的key设置为这次访问的查询条件(redis不是关系型数据库没有带条件查询的功能)如果下次访问还是相同的条件则直接可以从缓存中拿取数据。