redis实例的特点
Redis是一个字典结构的存储服务器,而实际上一个redis实例提供了多个用来存储数据的字典,客户端可以将数据指定存放到那个字典中。
每个数据库对外都是从0开始的递增数字命名,redis默认支持16个数据库,可以更改配置参数databases来修改这个数字。默认选中0号数据库,也可以通过select名来更换数据库(下标 0-15)
注意:
1. redis不支持自定义数据库的名字
2. 多个数据库之间不是完全隔离的,比如FLUSHALL清空redis实例中的所有数据库的数据,这些数据库更像是命名空间,
不适合存放不同应用的数据,但是可以将一个应用不同环境的数据放在不同数据库中。
3. 不同应用创建不同的redis实例存放数据,redis实例占用内存只有1Mb,不同担心多个实例占用很多内存
热身:基本命令
1. 查找键 keys pattern,举个例子查询 abc键 , keys **abc**
2. 判断键key是否存在, exists key 返回1 存在,返回0 ,不存在
3. 删除键 del key [key...] 删除一个或者多个键, 返回的是删除键的个数
Note: del命令不支持通配符,但是我们可以结合linux的管道和xarge命令自动实现删除所有匹配规则的键,比如,要删除
user:开头的键,就可以执行 redis-cli keys "user:*" |xargs redis-cli del 。另外由于del命令支持多个键作为参数,所以还可以执行 redis-cli del 'redis-cli keys "user:*"',具有同样的效果,但是性能更好
4 . 获取键值的数据类型 type keyname
返回值可以是string(字符串类型),hash(散列类型),list(列表类型),set(集合类型),zset(有序集合类型)
5. expire key second 设置key的存活时间(秒)
6. ttl key 查看key的存活时间(秒)
7. flushdb 清空数据库
8. redis的所有命令都是原子操作
字符串类型
字符串类型是redis中最基本的数据类型,能存储任何形式的字符串,包括二进制的数据,可以存放json化的对象甚至是一张图片,一个字符串类型键允许存放的最大容量是512Mb
命令
1. 赋值和取值 set key value / get key (当键不存在返回空)
2. 递增数字 incr key 当存储的字符串是整数形式时候,递增当前键值,返回的是递增后的值
(当操作的键不存在时候会默认键值为0,incr key 会返回1 ,当然当键不是整数时候会报错的)
3. 减少 decr key / decrby key decrement
4. 增加指定浮点数 incrbyfloat key increment
5. 向尾部加值 append key value append 的作用是向键值的末尾加上value,如果键不存在则将该键设置为value,相当
域set key value,返回值是追加后字符串的总长度
set key hello
append key " world!" append 命令的第二个参数加了双引号,原因是包含空格。在redis-cli 中输入需要双引号区分
6. strlen key 命令返回键值的长度,不过不存在返回0
7. mget key[key...] / mset key value [key value ...] 同时获取/设置多个键值
实践
1> 文章访问量统计
博客的常见的功能是统计文章的访问量,可以为每篇文章使用一个名为post:文章id:page.view的键来记录文章的访问量,每次访问文章的时候使用incr命令自增
note: redis推荐使用"对象类型:对象ID:对象属性"来命名一个键,如使用键user:1:friends来存储id为1的用户的好友列表,对于多个单词则推荐使用. 分隔,命名最好有意义,便于查找
2>INCR命令生成自增ID,举个例子来说,使用INCR命令建立的键的初始键值是1,所以可以很容易得知, INCR命令的返回值既是加入该对象后的当前类型的对象总数,又是该新增对象的ID。
3>存放文章数据。由于每个字符串类型键只能存储一个字符串,而一篇博客文章是由标题、正文、作者与发布时间等多个元素构成的。为了存储这些元素,我们需要使用序列化函数(如PHP中的 serialize和JavaScript中的 JSON.stringify)将它们转换成一个字符串。除此之外因为字符串类型键可以存储二进制数据,所以也可以使用MessagePack进行序列化,速度更快,占用空间也更小。
位操作
一个字节表示为8个二进制位,比如说 a (97) 表示为16进制 0x61,二进制为 0110 0001
getbit key offset 获取索引位置的对应的二进制数, 最右边 index 为 0 ,往左边索引递增,offset超出,则返回0
setbit key offset value 设置索引位置的二进制数的值,返回的是旧值,设置的索引长度超出键的二进制长度,将中间的二进制数设置为0,同理的设置一个不存的键指定二进制位的值,会自动将前面的位赋值为0
bitcount key 获取字符串类型键中值是1的二进制的个数,可以通过参数来限制统计的字节范围
bitcount foo 0 1 则统计前两个字节的值是1 的二进制个数
BITOP命令可以对多个字符串类型键进行位运算,并将结果存储在destkey参数指定的键中,支持AND,OR,XOR,NOT
SET foo1 bar
SET foo2 aar
BITOP or res foo1 foo2 将 foo1 和foo2位运算的结果放在res中
BITPOS key 0/1 :获得键的第一个位值是0或1的偏移量 例如:BITPOS foo 0 / BITPOS foo 1
注意: BITPOS命令的第二个和第三个参数分别指定要查询的起始字节和结束字节(字节同样从0开始算起),返回的偏移量是从
头开始算起的,而不是从起始字节开始算。
,例如:查询第二个字节和第三个字节之间出现第一个值为1 的二进制位的偏移量
BITPOS foo 1 1 2
注意: 如果不设置结束字节并且键值的所有二进制位都是1,则当要查询值为0的二进制位偏移量的时候,返回结果是键值长度的下一个字位的偏移量 .举例来说 0xff 表示为 /xff,如果获取二进制位为0的偏移量,结果就是键值的长度
实践
1>使用位运算来存储用户的性别,比如用户有个用户id,设置一个字符创类型的键sexkey存放所有用户性别,用户性别用0和1表示,男 1 女 0
用户id同样是redis自增生成的,那么通过 setbit sexkey userid 0/1 这个命令设置每个用户性别,就只用一个
key就能记录完全。
setbit sexkey userid 0/setbit key userid 1 ,将用户id作为偏移量设置,通过userid 就能够获取到对应的性别
getbit sexkey userid 这个命令来获取用户的性别
2>使用setbit命令时,如果当前键的键值长度小于要设置的二进制位的偏移量时,redis会自动分配内存并将键值的当前长度到指定的偏移量之间的二进制位都设置为0,可能造成资源的浪费和服务器的阻塞
还是刚才网站存放用户性别的例子,如果网站的用户id是从10000001开始的,那么会造成10多MB的浪费,正确的做法是每个用户的ID减去1000000在进行存储
散列类型
散列类型的键值也是一种字典机结构,其存储了字段和字段值的映射,但是字段值只能是字符串,不支持其他数据类型
提示: 除了散列类型,redis的其他数据类型同样不支持数据类型的嵌套,比如集合类型的每个元素都只能是字符串,不能是另一个集合或散列表等。
散列类型适合存储对象:使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。
在关系型数据库中如果要给某行记录加一个属性,表的结构就要发生改变,而redis散列类型不用,完全可以自由地为任何键增减字段而不影响其他键。
命令
1. 赋值和取值
HSET key field value 设置字段的值
HGET key field 获取字段的值
HMSET key field value [field value ....] 设置多个字段的值
HMGET key field [field...] 获取多个字段的值
HGETALL key 返回的结构是字段和字段值组成的列表,不是很直观,很多语言的redis客户端,将返回结构封装为对象。
HEXISTS key field 判断一个字段是否存在,存在返回1,不存在返回0
hsetnx key field value hsetnx和hset命令类似,区别在于 hsetnx如果key存在将不做任何操作,不存在才会去赋值。
HINCRBY key field increment 指定增加字段值指定的整数
hdel key field[field...] 删除一个或者多个字段,返回的是被删除的字段个数
Note:
1. HSET命令的方便之处在于不区分插入和更新操作,这意味着修改数据时候不用事先判断字段是否存在来决定要执行插入还是更新,当执行的是插入操作是hset命令会返回1,当执行的是更新操作时hset返回0,更进一步,当键本身不存在时候,hset命令还会自动创建
2. 在Redis中每个键都属于一个明确的数据类型,使用一种数据类型的命令操作另一种数据类型的键会报错
(不是所有命令都是如此,比如set命令可以覆盖已经存在的键而不论原来的键是什么类型)
实践
1.存储文章数据
使用字符串类型存储文章数据,无法提供对单个字段的原子读写操作支持。从而产生竞态条件。
可以使用散列类型存储文章的数据.这个方法的好处是无论获取还是修改文章数据,都可以对单一属性操作。
键 键值
post:42:title -------------> 第一篇日志
psot:42:author --------------> 小白
2.存储文章缩略名
每个文章的缩略名必须是唯一的,所以在发布文章时程序需要验证用户输入的缩略名是否存在,同时也需要通过缩略名获得文章的ID。
我们可以使用一个散列类型的键slug.to.id来存储文章缩略名和ID之间的映射关系。其中字段用来记录缩略名,字段值用来记录缩略名对应的ID。这样就可以使用HEXISTS命令来判断缩略名是否存在,使用HGET命令来获得缩略名对应的文章ID了
命令拾遗
1. 只获取字段名 hkeys key 只获取字段值 hvals key
2. 获得字段数量 HLEN key