Redis的简单使用
Jedis入门
Jedis介绍
-
Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。
-
在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推荐使用Jedis和Redisson。
-
Redis的Windows客户端(默认使用db0库)
Java连接Redis
- 导包jar包
-
单测试连接
public static void main(String[] args) { // 获取Jedis连接 Jedis jedis = new Jedis("IP地址", 6379); // 使用Jedis操作Redis数据库(String类型) jedis.set("username", "sunwukong"); String username = jedis.get("username"); System.out.println(username); // 使用Jedis操作Redis数据库(set类型) jedis.hset("mysetjava", "name", "zhubajie"); String setName = jedis.hget("mysetjava", "name"); System.out.println(setName); // 使用Jedis操作Redis数据库(list类型) jedis.lpush("mylistjava", "zhangwuji", "北京", "20"); List<String> list2 = jedis.lrange("mylistjava", 0, -1); String list = jedis.lpop("mylistjava"); System.out.println(list2); System.out.println(list); // 使用Jedis必须关闭数据库 jedis.close(); }
-
数据库连接池的方式进行连接(单连接)
public static void main(String[] args) { // 创建Jedis连接池的配置对象 JedisPoolConfig jpc = new JedisPoolConfig(); // 设置最大连接数 jpc.setMaxTotal(20); jpc.setMaxWaitMillis(8000); // 创建数据库连接池 JedisPool pool = new JedisPool(jpc, "IP地址", 6379); Jedis jedis = pool.getResource(); String username = jedis.get("username"); System.out.println(username); jedis.close(); }
-
抽取成工具类
public class JedisPoolUtils { private static JedisPool jedisPool = null; private static JedisPoolConfig jedisPoolConfig = null; private static int maxTotal = 0; private static long maxWaitMillis = 0; private static String host = null; private static int port = 0; static { // 加载属性 jedisPoolConfig = new JedisPoolConfig(); ResourceBundle bundle = ResourceBundle.getBundle("jedis"); maxTotal = Integer.parseInt(bundle.getString("maxTotal")); maxWaitMillis = Long.parseLong(bundle.getString("maxWaitMillis")); host = bundle.getString("host"); port = Integer.parseInt(bundle.getString("port")); // 加载配置 jedisPoolConfig.setMaxTotal(maxTotal); jedisPoolConfig.setMaxWaitMillis(maxWaitMillis); jedisPool = new JedisPool(jedisPoolConfig, host, port); } public static Jedis getRedis() { return jedisPool.getResource(); } }
-
properties配置文件
maxTotal=20 maxWaitMillis=8000 host=IP地址 port=6379
Redis特性
多数据库
-
一个Redis实例可以包括多个数据库,客户端可以指定连接某个redis实例的哪个数据库,就好比一个mysql中创建多个数据库,客户端连接时指定连接哪个数据库。
-
一个redis实例最多可提供16个数据库,下标从0到15,客户端默认连接第0号数据库,也可以通过select选择连接哪个数据库,如下连接1号库:
-
将 newkey 移植到1号库
move newkey1:将当前库的key移植到1号库中
-
ping,测试连接是否存活
-
echo,在命令行打印一些内容
-
select,选择数据库。Redis数据库编号从0“15,可以选择任意一个数据库来进行数据的存取。
-
quit,退出连接。
-
dbsize,返回当前数据库中key的数目。
-
info,获取服务器的信息和统计。
-
flushdb,删除当前选择数据库中的所有key。
-
flushall,删除所有数据库中的所有key。
消息订阅与发布
命令 | 描述 |
---|---|
subscribe channel | 订阅频道,例:subscribe mychat,订阅mychat这个频道 |
psubscribe channel* | 批量订阅频道,例:psubscribes my*,订阅以”my”开头的频道 |
publish channel content | 在指定的频道中发布消息,如publish mychat ‘today is a newday’ |
-
步骤1:在第一个连接中,订阅mychat频道。此时如果没有人“发布”消息,当前窗口处于等待状态。
-
步骤2:在另一个窗口中,在mychat频道中,发布消息。
-
第一个连接收到发布的消息
-
步骤3:批量订阅以my开头所有频道。
-
步骤4:在第二个窗口,分别在“mychat1”和“mych”发布消息
-
批量订阅窗口接收消息
redis事务
概述
- 和众多其它数据库一样,Redis作为NosQL数据库也同样提供了事务机制。在Redis中,MULTI/EXEC/DISCARD/这三个命令是我们实现事务的基础。
Redis事务的特性
-
在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行
-
和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
-
我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为“BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。
-
在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。
-
当使用Append-Only模式时,Redis 会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。
此时,我们就要充分利用Redis 工具包中提供的redis-check-aof工具,该工具可以帮助我们定位。
到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。命令 解释 multi 开启事务用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才会被原子的执行,类似与关系型数据库中的:begin transaction exec 提交事务,类似与关系型数据库中的:commit discard 事务回滚,类似与关系型数据库中的:rollback
Redis持久化
概述
-
Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化。
-
Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。
-
RDB持久化(默认支持,无需配置)
该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
-
AOF持久化
该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。 -
无持久化
我们可以通过配置的方式禁用Redis服务器的持久化功能,这样我们就可以将Redis视为一个功能加强版的memcached了。 -
redis 可以同时使用RDB和AOF
RDB方式
优势
- RDB是将执行的结果,在指定的时间内进行一次保存**(保存的结果)**
- 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
- 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上
- 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork(分叉)出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行10操作了。
- 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
劣势
- 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。
因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。 - 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟
快照参数设置
-
save9001#每900秒(15分钟)至少有1个key发生变化,则dump内存快照。
-
save 30010#每300秒(5分钟)至少有10个key发生变化,则dump内存快照
-
save 6010000#每60秒(1分钟)至少有10000个key发生变化,则dump内存快照
AOF方式
- AOF是将整个执行的过程存储到了aof文件中了
优势
- 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
- 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis 下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
- 如果日志过大,Redis可以自动启用rewrite机制。即Redis 以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。
因此在进行rewrite切换时可以更好的保证数据安全性。 - AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
劣势
- 对于相同数量的数据集而言,AOF文件通常要大于RDB文件
- 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
配置 | 配置描述 |
---|---|
always | 每次有数据修改发生时都会写入AOF文件 |
everysec | 每秒钟同步一次,该策略为AOF的缺省策略 |
no | 从不同步。高效但是数据不会被持久化 |
Redis使用场景
-
取最新N个数据的操作
比如典型的取你网站的最新文章,通过下面方式,我们可以将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取(1)使用LPUSH latest.comments<ID>命令,向list集合中插入数据
(2)插入完成后再用LTRIM latest.comments 0 5000命令使其永远只保存最近5000个ID
(3)然后我们在客户端获取某一页评论时可以用下面的逻辑
-
排行榜应用,取TOPN操作
这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。 -
需要精准设定过期时间的应用
比如你可以把上面说到的sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。 -
计数器应用
Redis的命令都是原子性的,你可以轻松地利用INCR,DECR命令来构建计数器系统。 -
Uniq操作,获取某段时间所有数据排重值
这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。 -
实时系统,反垃圾系统
通过上面说到的set功能,你可以知道一个终端用户是否进行了某个操作,可以找到其操作的集合并进行分析统计对比等。没有做不到,只有想不到。 -
Pub/Sub构建实时消息系统
Redis的Pub/Sub系统可以构建实时的消息系统,比如很多用Pub/Sub构建的实时聊天系统的例子。 -
构建队列系统
使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。
部分来源于网络