参考文章:http://www.jb51.net/article/56448.htm
一、redis数据类型
·1.1 字符串-strings
有人说,如果只使用redis中的字符串类型,且不使用redis的持久化功能,那么,redis就和memcache非常非常像了。这说明strins类型是一个很基础的数据类型,也是任何存储系统都必须必备的数据类型。字符串类型是二进制安全的。
1、set
创建string。注意:此命令默认会覆盖已存在key的值。
用法:
set JOAN DORA set JOAN DORA nx -->如果存在key为JOAN时,则会失败 set JOAN DORA xx -- >成功
2、incr
如果value是数字类型(当然也是string的),可以使用此命令,进行加法操作。
用法:
set counter 100 incr counter -->101 incrby counter 49 -->150
在遇到数值操作时,redis会将字符串类型转换为数值。由于INCR等指令本身就具有原子操作的特性,所以我们完全可以利用redis的INCR、INCRBY、DECR、DECRBY等指令来实现原子计数的效果。假如,在某种场景下有三个客户端同时读取了mynum的值(值为2),然后对其同时进行了加1操作,那么,最后mynum的值一定是5。不少网站都利用redis的这个原子特性来实现业务上的统计计数需求。
3、get
取值,用法:
get JOAN -->DORA
1.2 列表-lists
rdis中的lists在底层实现并不是数组,而是链表,也就是对于一个具有上百万个元素的lists来说,在头部和尾部插入一个新元素,其时间复杂度是常数级别的。虽然lists有这样的优势,但同样尤其弊端,那就是,链表型lists的元素定位会比较慢,而数组型lists的元素定位就会快很多。
lpush、rpush、lrange
redis 的一种数据结构:双端列表。lpush是将alue放到列表的头部,rpush是将value放在列表的尾部。
用法:
rpush mylist a rpush mylist b lpush mylist first lrange mylist 0 -1 -->0代表列表的第一个 -1代表列表的最后一个 -2 是倒数第二个 rpush mylist a b c d "JOANDORA" --> 连续存放多个值
应用场景:
1、我们可以利用lists来实现一个消息队列,而且可以确保先后顺序,不必像Mysql那样还要通过order by来进行排序。
2、利用lrange可以很方便的实现分页功能。
3、在博客系统中,没篇博文的评论也可以存入一个单独的lists中。
1.3 无序不重复集合 set
redis中的集合是一种无序的集合集合相关的操作也很丰富,如添加删除已有元素,取交集、并集、差集等。
用法:
//向集合myset中加入一个新元素"one" 127.0.0.1:6379> sadd myset "one" (integer) 1 127.0.0.1:6379> sadd myset "two" (integer) 1 //列出集合myset中的所有元素 127.0.0.1:6379> smembers myset 1) "one" 2) "two" //判断元素1是否在集合myset中,返回1表示存在 127.0.0.1:6379> sismember myset "one" (integer) 1 //判断元素3是否在集合myset中,返回0表示不存在 127.0.0.1:6379> sismember myset "three" (integer) 0 //新建一个新的集合yourset 127.0.0.1:6379> sadd yourset "1" (integer) 1 127.0.0.1:6379> sadd yourset "2" (integer) 1 127.0.0.1:6379> smembers yourset 2) "2" //对两个集合求并集 127.0.0.1:6379> sunion myset yourset 1) "1" 2) "one" 3) "2" 4) "two"
1.4 有序不重复集合 sorted set
有序集合中的每个元素都关联一个序号(score),这便是排序的依据。很多时候,我们都将redis中的有序集合叫做zsets。这是因为在redis中,有序集合相关的操作指令都是以z开头,比如:zrange、zadd等。
zadd 1 a --> 1是排序 zrange myset 0 -1 --> 查看集合元素 zrevrange myset 0 -1 --> 查看集合元素,反向 zrange myset 0 -1 withscores --> 打印元素的时候,间隔打印出序号
1.5 哈希-hashes
哈希是从redis-2.0版本之后才有的数据结构。hashes存的是字符串和字符串值之间的映射,比如一个用户要存储其全名、姓氏、年龄等等,就很适用hashes。
hmset key field value --> 将多个field-vaue存放到key中 hmset webset google www.google.com baidu www.baidu.com hmget webset google hget webset yahoo --> 能查,不过结果为空 hincrby user age 10 --> 给hash中age加10
二、其他操作命令
2.1、mset、mget
可同时完成多个key-value存取值
用法:
mset a 10 b 20 c 30 mget a b c
2.2、del
删除key-value
用法:del mylist
2.3、pop
取值,和push类似,也是分左和右。
用法:rpop mylist
lpop mylist
三、事务处理
总所周知,事务是指一个完整的动作,要么全部执行,要么全部失败。
事务的四大特性(简称ACID): 1、原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部执行,要么均不执行。 2、一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。 3、隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。 4、持久性(Durability):对于任意提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。
在聊redis事务处理之前,要先和大家介绍四个redis指令,即MULTI,EXEC,DISCARD,WATCH。这四个指令构成了redis事务处理的基础。
1、MULTI:组装一个事务
2、EXEC:执行一个事务
3、DISCARD:取消一个事务
4、WATCH:监视一些key,一旦这些key在事务执行前被改变,则取消事务的执行。
例子1:简单粗暴:
redis> MULTI //标记事务开始 OK redis> INCR user_id //多条命令按顺序入队 QUEUED redis> INCR user_id QUEUED redis> INCR user_id QUEUED redis> PING QUEUED redis> EXEC //执行 1) (integer) 1 2) (integer) 2 3) (integer) 3 4) PONG解释:QUEUED表示我们在用MULTI组装事务时,每一个命令都会进入到内存队列中缓存起来,如果出现QUEUED则表示我们这个命令成功插入了缓存队列,在将来执行EXEC时,这些被QUEUED的命令都会被组装成一个事务来执行(如果中途语句出错,则执行命令EXEC会失败)。
例子2:有关事务,大家经常会遇到两种错误
1、调用EXEC之前错误
2、调用EXEC之后错误
”调用EXEC之前错误“有可能是语法有误导致,也可能是由于内存不足导致的。只要出现某个命令无法成功写入缓冲队列的情况,redis也会进行记录,在客户端调用EXEC时,redis会拒绝这一事务(这是redis2.6.5之版本之后的策略。在2.6.5之前的版本中,redis会忽略那些入队失败的命令,只执行那些入队成功的命令)。
127.0.0.1:6379> multi OK 127.0.0.1:6379> haha //一个明显错误的指令 (error) ERR unknown command 'haha' 127.0.0.1:6379> ping QUEUED 127.0.0.1:6379> exec //redis无情的拒绝了事务的执行,原因是“之前出现了错误” (error) EXECABORT Transaction discarded because of previous errors.
“调用EXEC之后错误”redis采取了完全不同的策略,即redis不会理睬这些错误,而是继续向下执行事务中的其他命令。这是因为,对于应用层面对错误,并不是redis自身需要考虑和处理的问题所以一个事务中如果一条命令执行失败了,并不会影响接下来的其他命令的执行。
127.0.0.1:6379> multi OK 127.0.0.1:6379> set age 23 QUEUED //age不是集合,所以如下是一条明显错误的指令 127.0.0.1:6379> sadd age 15 QUEUED 127.0.0.1:6379> set age 29 QUEUED 127.0.0.1:6379> exec //执行事务时,redis不会理睬第2条指令执行错误 1) OK 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 3) OK 127.0.0.1:6379> get age "29" //可以看出第3条指令被成功执行了
再来说下WATCH,这是一个很好的命令,它可以帮我们很好的实现类似于乐观锁的效果,即CAS(Check And Set)。WATCH本身的作用是监视key是否被改动过,而且支持同时监视多个key,只要还没出发事务,WATCH都会尽职尽责的监视,一旦发现谋个key被修改了,在执行EXEC时就会返回nil,表示事务无法触发。
127.0.0.1:6379> set age 23 OK 127.0.0.1:6379> watch age //开始监视age OK 127.0.0.1:6379> set age 24 //在EXEC之前,age的值被修改了 OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> set age 25 QUEUED 127.0.0.1:6379> get age QUEUED 127.0.0.1:6379> exec //触发EXEC (nil) //事务无法被执行