NoSQL数据库之Redis

NoSQL

为什么用NoSQL

NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。

谷歌或Facebook每天为他们的用户收集万亿比特的数据,这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展

优势:

  • 易扩展
  • 大数据量高性能:一秒读11万,写7万次
  • 多样灵活的数据模型

阿里巴巴的数据存储

  1. 基本数据信息:名称、价格,出厂日期,生产厂商等
    MySQL数据库
  2. 商品描述、详情、评价信息(多文字类)
    文档数据库MongDB
  3. 商品图片
    淘宝自己的TFS
  4. 商品的关键字
    搜索引擎ISearch、Solr
  5. 商品的波段性的热点高频信息
    内存数据库:tair、Redis、Memcache
  6. 商品的交易、价格计算、积分累计
    支付宝接口

NoSQL数据模型

聚合模型:

  • KV键值对 Redis
  • 文档型数据库(bson较多)Mongodb
  • 列族
  • 图形
{
 "customer":{
   "id":1136,
   "name":"Z3",
   "billingAddress":[{"city":"beijing"}],
   "orders":[
    {
      "id":17,
      "customerId":1136,
      "orderItems":[{"productId":27,"price":77.5,"productName":"thinking in java"}],
      "shippingAddress":[{"city":"beijing"}]
      "orderPayment":[{"ccinfo":"111-222-333","txnid":"asdfadcd334","billingAddress":{"city":"beijing"}}],
      }
    ]
  }
}

CAP

分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容忍性(P:Partition Tolerance),最多只能同时满足其中两项。


一致性

一致性指的是多个数据副本是否能保持一致的特性,在一致性的条件下,系统在执行数据更新操作之后能够从一致性状态转移到另一个一致性状态。

对系统的一个数据更新成功之后,如果所有用户都能够读取到最新的值,该系统就被认为具有强一致性。

可用性

可用性指分布式系统在面对各种异常时可以提供正常服务的能力,可以用系统可用时间占总时间的比值来衡量,4个9的可用性表示系统 99.99% 的时间是可用的。

在可用性条件下,要求系统提供的服务一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。

分区容忍性

网络分区指分布式系统中的节点被划分为多个区域,每个区域内部可以通信,但是区域之间无法通信。

在分区容忍性条件下,分布式系统在遇到任何网络分区故障的时候,仍然需要能对外提供一致性和可用性的服务,除非是整个网络环境都发生了故障。

权衡

在分布式系统中,分区容忍性必不可少,因为需要总是假设网络是不可靠的。因此,CAP 理论实际上是要在可用性和一致性之间做权衡

可用性和一致性往往是冲突的,很难使它们同时满足。在多个节点之间进行数据同步时,

  • 为了保证一致性(CP),不能访问未同步完成的节点,也就失去了部分可用性;
  • 为了保证可用性(AP常用),允许读取所有节点的数据,但是数据可能不一致。

数据库:

  • CA 传统Oracle数据库
  • AP 大多数网站架构的选择
  • CP Redis、Mongodb

Base

BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。

BASE其实是下面三个术语的缩写:

  • 基本可用(Basically Available)
  • 软状态(Soft state)
  • 最终一致(Eventually consistent)

它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观,缘由在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一种方式来完成,这里BASE就是解决这个问题的办法。

什么是Redis

Redis是Remote Dictionary Server(远程数据服务)的缩写
是由意大利人antirez开发的一款内存高速缓存数据库(而MySQL数据库中的数据存放在硬盘中)。该软件采用C语言编写,数据模型为key-value,它具有丰富的数据结构、可持久化,保证了数据的安全。

对于新闻页面,可以采用页面缓存,常用在CMS内存管理系统中;
对于商城商品,各个部分业务比较独立,可以采用数据缓存,Redis即是数据缓存,可以减轻数据库的负载;
取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面。

Redis的安装与启动

安装

  1. 下载稳定版 redis( http://redis.io/download )
  2. 将下载的压缩文件 redis-2.6.15.tar.gz传入Linux系统
  3. 进入压缩包所在目录并解压文件
tar zxvf redis-2.6.15
  1. make redis-2.6.15即可自动安装
  2. 若出现command not found CC 的错误,则说明没有安装gcc环境,安装即可
yum -y install gcc
  1. 若出现报错 zmalloc.h:50:31: 错误:jemalloc/jemalloc.h,输入下面语句:
make MALLOC=libc
  1. make成功后会在src文件夹下产生一些二进制可执行文件,包括redis-server、redis-cl等
$ find . -type f -executable
./redis-benchmark //用于进行redis性能测试的工具
./redis-check-dump //用于修复出问题的dump.rdb文件
./redis-cli //redis的客户端
./redis-server //redis的服务端
./redis-check-aof //用于修复出问题的AOF文件
./redis-sentinel //用于集群管理

启动

./redis-server 

即在前端启动了Redis
在这里插入图片描述输入Ctrl+C即可停止服务。

修改redis.conf配置文件,daemonize = yes 设置为后台启动:

./redis-server redis.conf 

简单使用

./redis-cli   //启动Redis客户端
redis 127.0.0.1:6379> set name tom
OK
redis 127.0.0.1:6379> get name
"tom"

关闭操作:

redis 127.0.0.1:6379> SHUTDOWN
redis 127.0.0.1:6379> EXEC

说明

  • 单进程
  • 默认16个数据库,类似数组下表从零开始,初始默认使用零号库,可以使用SELECT <dbid>命令在连接上指定数据库id;
  • dbsize查看当前数据库的key的数量
  • flushdb:清空当前库
  • flushall:通杀全部库
  • 统一密码管理,16个库都是同样密码,要么都连上,要么一个也连接不上
  • Redis索引都是从零开始
  • 默认端口是6379

五大数据类型

  • String(字符串)
  • Hash(哈希)
  • List(列表):本质是链表
  • Set(集合)
  • Zset(sorted set:有序集合)

http://redisdoc.com/

key的操作

redis本质上是一个key-value 数据库,在Redis中,key除了**‘空格’和‘/n’**不能作为名字的组成外,其它均可。
注意:

  1. key不要太长,尽量不要超过1024字节,这不仅消耗内存,而且会降低查找的效率;
  2. key也不要太短,太短的话,key的可读性会降低;
  3. 在一个项目中,key最好使用统一的命名模式,例如user:10000:passwd。

key的相关命令
在这里插入图片描述

redis 127.0.0.1:6379> exists name
(integer) 1

redis 127.0.0.1:6379> type name
string

redis 127.0.0.1:6379> keys a*
1)"addr"
2)"age"

redis 127.0.0.1:6379> dbsize
(integer) 4

redis 127.0.0.1:6379> del jf0ej093jrjfpkefplk%%&*()
(integer) 1

redis 127.0.0.1:6379> rename age mingzi
OK
redis 127.0.0.1:6379> select 1   //选择第二个数据库(下标从0开始)
OK
redis 127.0.0.1:6379> flushdb
OK

String类型操作

如果只使用redis中的字符串类型,且不使用redis的持久化功能,那redis就memcache类似了,这说明strings类型是一个很基础的数据类型,也是任何存储系统都必备的数据类型。我们甚至可以把一个图片文件的内容作为字符串来存储。

常用操作:
在这里插入图片描述

redis 127.0.0.1:6379> mset color1 red color2 green color3 blue
OK
redis 127.0.0.1:6379> mget color1 color2 color3

incr key :对key的值做加加操作,并返回新的值。注意incr一个不是int的value会返回错误,incr一个不存在的key,则设置key为1。

redis 127.0.0.1:6379> incr num
(integer) 1
redis 127.0.0.1:6379> get num
"1"
redis 127.0.0.1:6379> incr num
(integer) 2
redis 127.0.0.1:6379> get num
"2"

redis 127.0.0.1:6379> incrby num 30
(integer) 32

redis 127.0.0.1:6379> append color3 andyellow
redis 127.0.0.1:6379> get color3
"blueandyellow"

redis 127.0.0.1:6379> substr color3 4 6
"and"

getrange:获取指定区间范围内的值,类似between…and的关系
从零到负一表示全部;setrange设置指定区间范围内的值:

redis 127.0.0.1:6379> set k1 tjtulong
OK
redis 127.0.0.1:6379> getrange k1 2 8
"tulong"

setex:设置带过期时间的key,动态设置。

redis 127.0.0.1:6379> setex k2 10 xiao
OK
redis 127.0.0.1:6379> ttl k2
(integer) 5
redis 127.0.0.1:6379> get k2
(nil)

setnx:只有在 key 不存在时设置 key 的值。

List链表类型

redis的list类型其实就是一个每个子元素都是string类型的双向链表。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。
例如:一个网页想获得最近登录系统的前10个用户,如果用MySQL则需要对整个表进行操作,消耗资源,如果用Redis链表即可快速保存和获取。
List常用操作:
在这里插入图片描述保存最新登录的5个用户:

redis 127.0.0.1:6379[1]> lpush newlogin tom
(integer) 1
redis 127.0.0.1:6379[1]> lpush newlogin mary
(integer) 2
redis 127.0.0.1:6379[1]> lpush newlogin linken
(integer) 3
redis 127.0.0.1:6379[1]> lpush newlogin xiaoming
(integer) 4
redis 127.0.0.1:6379[1]> lpush newlogin jack
(integer) 5
redis 127.0.0.1:6379[1]> lpush newlogin xiaoli
(integer) 6
redis 127.0.0.1:6379[1]> rpop newlogin
"tom"

//通过范围查找链表中元素
redis 127.0.0.1:6379[1]> lrange newlogin 0 4
1) "xiaoli"
2) "jack"
3) "xiaoming"
4) "linken"
5) "mary"

通过索引获取列表中的元素 lindex key index

ltrim key 开始index 结束index,截取指定范围的值后再赋值给key

在list某个已有值的前后再添加具体值: linsert key before/after 值1 值2

链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率较低了。

Set集合类型

Redis的Set是String类型的无序集合,Set元素最大可以包含(2的32次方-1)个元素,Set的是通过Hashtable实现的,Hashtable会随着添加或者删除自动的调整大小。
Set集合类型除了基本的添加删除操作,其他有用的操作还包含集合的取并集(union),交集(intersection),差集(difference),可用好友推荐功能。
在这里插入图片描述

redis 127.0.0.1:6379[1]> sadd tomFri mary
(integer) 1
redis 127.0.0.1:6379[1]> sadd tomFri jack
(integer) 1
redis 127.0.0.1:6379[1]> sadd tomFri xiaoming
(integer) 1
redis 127.0.0.1:6379[1]> sadd tomFri wangwu
(integer) 1
redis 127.0.0.1:6379[1]> sadd linkenFri yuehan
(integer) 1
redis 127.0.0.1:6379[1]> sadd linkenFri daxiong
(integer) 1
redis 127.0.0.1:6379[1]> sadd linkenFri xiaoming
(integer) 1
redis 127.0.0.1:6379[1]> sadd linkenFri wangwu
(integer) 1

//取交集和并集
redis 127.0.0.1:6379[1]> sinter tomFri linkenFri
1) "xiaoming"
2) "wangwu"
redis 127.0.0.1:6379[1]> sunion tomFri linkenFri
1) "yuehan"
2) "mary"
3) "daxiong"
4) "xiaoming"
5) "jack"
6) "wangwu"
redis 127.0.0.1:6379[1]> smove tomFri linkenFri mary
(integer) 1
redis 127.0.0.1:6379[1]> scard tomFri
(integer) 3

SortSet排序集合类型

和Set一样SortedSet也是String类型元素的集合,不同的是每个元素都会关联一个double类型的score。SortedSet的实现是skip list和Hashtable的混合体。当元素被添加到集合中时,一个元素到score的映射被添加到hash table中,另一个score到元素的映射被添加到skip list并按照score排序,所以就可以有序的获取集合中的元素
每个元素都是值+权的组合;
在这里插入图片描述

应用案例:获得热门帖子回复量信息

redis 127.0.0.1:6379[1]> zadd hotmessage 102 11
(integer) 1
redis 127.0.0.1:6379[1]> zadd hotmessage 141 12
(integer) 1
redis 127.0.0.1:6379[1]> zadd hotmessage 159 13
(integer) 1
redis 127.0.0.1:6379[1]> zadd hotmessage 72 14
(integer) 1
redis 127.0.0.1:6379[1]> zrevrange hotmessage 0 100
1) "15"
2) "13"
3) "12"
4) "11"
5) "14"
//删除排名倒数第一的元素
redis 127.0.0.1:6379[1]> zremrangebyrank hotmessage 0 0
(integer) 1
redis 127.0.0.1:6379[1]> zrevrange hotmessage 0 100
1) "15"
2) "13"
3) "12"
4) "11"

Hash类型

hashes,即哈希。哈希是从redis-2.0.0版本之后才有的数据结构。hashes存的是字符串和字符串值之间的映射,比如一个用户要存储其全名、姓氏、年龄等等,就很适合使用哈希。

hset:建立哈希并赋值
hget:取值
hmset:建立哈希表
hmget:获取值
hgetall:获取所有
hdel:删除

//建立哈希,并赋值
127.0.0.1:6379> HMSET user:001 username antirez password P1pp0 age 34 
OK
//列出哈希的内容
127.0.0.1:6379> HGETALL user:001 
1) "username"
2) "antirez"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
//更改哈希中的某一个值
127.0.0.1:6379> HSET user:001 password 12345 
(integer) 0
//再次列出哈希的内容
127.0.0.1:6379> HGETALL user:001 
1) "username"
2) "antirez"
3) "password"
4) "12345"
5) "age"
6) "34"

配置文件redis.conf

UNITS

  1. 配置大小单位,开头定义了一些基本的度量单位,只支持bytes,不支持bit
  2. 对大小写不敏感

INCLUDES
可以通过includes包含,redis.conf可以作为总闸,包含其他

GENERAL通用
设置ip地址,端口,超时时间等通用配置

SNAPSHOTTING快照、REPLICATION复制

SECURITY安全
可以设置密码config set requirepass '123456'

LIMITS限制

  • maxclients 最大连接数(默认无限制)
  • maxmemory 内存上限
  • maxmemory-policy 移除算法(lru、random、ttl)
  • maxmemory-samples 设置样本数量

持久化

Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化,这是相对memcache来说的一个大的优势。redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。

RDB持久化

在指定的时间间隔内将内存中的数据集快照写入磁盘(Snapshot快照),它恢复时是将快照文件直接读到内存里

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失,同时fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑。

快照是默认的持久化方式,一次性把Redis中全部数据保存在硬盘上。
快照持久化的储存文件为dump. rmp
快照保存配置:
save 900 1 900秒内如果超过1个key被修改,则发起快照保存
save 300 10 300秒内容如超过10个key被修改,则发起快照保存
数据修改的频率非常高,备份的频率也高。

在shutdown后会自动存储一次快照,也可以直接save(阻塞),执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义

手动快照持久化:./redis-cli bgsave

AOF持久化

开启AOF持久化(会将以前的数据删除),删除旧进程,开启新进程。
AOF方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍。

默认没有开启。
appendonly yes 开启
appendonly.aof文件保存

AOF持久化备份频率非常高
有三种方式如下(默认是:每秒fsync一次)

  1. appendonly yes //启用aof持久化方式
  2. appendfsync always //每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
  3. appendfsync everysec //每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
  4. appendfsync no //完全依赖os,性能最好,持久化没保证

注:dump.rmp和appendonly.aof同时存在时找appendonly.aof

为aof备份做优化处理(重写)
AOF采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令bgrewriteaof

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

./redis-cli bgrewiteaof

建议同时使用

因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。

如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写,可以改到适当的数值。

如果不Enable AOF,仅靠Master-Slave Replication实现高可用性也可以,能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构。

Redis的事务

一个队列中,一次性、顺序性、排他性的执行一系列命令。

redis 事务的相关命令:
enter description here

case1:正常事务

redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> set k1 v1
QUEUED
redis 127.0.0.1:6379> set k2 v2
QUEUED
redis 127.0.0.1:6379> get k2
QUEUED
redis 127.0.0.1:6379> EXEC
1) OK
2) OK
3) "v2"

case2:放弃事务

redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> set k1 v1
QUEUED
redis 127.0.0.1:6379> set k2 22
QUEUED
redis 127.0.0.1:6379> set k3 33
QUEUED
redis 127.0.0.1:6379> DISCARD
OK
redis 127.0.0.1:6379> get k2
"v2"

case3:全体连坐

redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> set k1 v1
QUEUED
redis 127.0.0.1:6379> set k2 v2
QUEUED
redis 127.0.0.1:6379> set k3 v3
QUEUED
redis 127.0.0.1:6379> getset k3
(error) ERR wrong number of arguments for 'getset' command
redis 127.0.0.1:6379> set k4 v4
QUEUED
redis 127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
redis 127.0.0.1:6379> get k4
(nil)

case4:冤头债主

redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> incr k1
QUEUED
redis 127.0.0.1:6379> set k2 22
QUEUED
redis 127.0.0.1:6379> set k3 33
QUEUED
redis 127.0.0.1:6379> get k3
QUEUED
redis 127.0.0.1:6379> EXEC
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "33"

说明Redis对事务部分支持

case5:watch监控

类似于乐观锁 CAS

client1:

redis 127.0.0.1:6379> WATCH balance
OK

clint2:对balance进行改变

redis 127.0.0.1:6379> set balance 800
OK

clint1:事务操作失败

redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> DECRBY balence 20
QUEUED
redis 127.0.0.1:6379> INCRBY debt 20
QUEUED
redis 127.0.0.1:6379> EXEC
(nil)
redis 127.0.0.1:6379> get balence
"800"

特性:

  • 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个问题,也没有行锁表锁的问题。
  • 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

主从模式

主从复制,即主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。

作用:

  • 读写分离
  • 容灾机制

一主二仆

从服务器命令

slaveof 192.168.39.159 6379

enter description here

通过命令info replication可以得到节点信息:是主还是从。

当主服务器断掉后,两个从服务器还是从服务器,依然只能读不能写;

当从服务器断掉后,再开启时,变为master。

薪火相传

上一个Slave可以是下一个Slave的Master,Slave同样可以接收其他
slaves的连接和同步请求,那么该slave作为了链条中下一个的master,
可以有效减轻master的写压力,去中心化

enter description here

79------>80------->81

反客为主

SLAVEOF no one变为主服务器

复制原理

slave启动成功连接到master后会发送一个sync命令,Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步。

全量复制: 而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制: Master继续将新的所有收集到的修改命令依次传给slave,完成同步。
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行

哨兵模式

概念:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

使用方式:

  1. 自定义的/myredis目录下新建sentinel.conf文件,名字绝不能错;
  2. 配置哨兵,填写内容:sentinel monitor 被监控数据库名字(自己起名字) 127.0.0.1 6379 1,最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机;
  3. 启动哨兵:redis-sentinel /myredis/sentinel.conf
  4. 正常主从操作;
  5. 原有的master挂了;
  6. 投票新选,产生新的master;
  7. 如果之前的master重启回来,成为slave;

复制的缺点

由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

Jedis

Java连接Redis

Maven坐标

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

连接服务器:

public class TestPing {
    public static void main(String[] args) 
    {
        Jedis jedis = new Jedis("127.0.0.1",6379);
        System.out.println(jedis.ping());
		// pong
    }
}

常用API

public class Test02 
{
  public static void main(String[] args) 
  {
     Jedis jedis = new Jedis("127.0.0.1",6379);
     //key
     Set<String> keys = jedis.keys("*");
     for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
       String key = (String) iterator.next();
       System.out.println(key);
     }
     System.out.println("jedis.exists====>"+jedis.exists("k2"));
     System.out.println(jedis.ttl("k1"));
     //String
     //jedis.append("k1","myreids");
     System.out.println(jedis.get("k1"));
     jedis.set("k4","k4_redis");
     System.out.println("----------------------------------------");
     jedis.mset("str1","v1","str2","v2","str3","v3");
     System.out.println(jedis.mget("str1","str2","str3"));
     //list
     System.out.println("----------------------------------------");
     //jedis.lpush("mylist","v1","v2","v3","v4","v5");
     List<String> list = jedis.lrange("mylist",0,-1);
     for (String element : list) {
       System.out.println(element);
     }
     //set
     jedis.sadd("orders","jd001");
     jedis.sadd("orders","jd002");
     jedis.sadd("orders","jd003");
     Set<String> set1 = jedis.smembers("orders");
     for (Iterator iterator = set1.iterator(); iterator.hasNext();) {
       String string = (String) iterator.next();
       System.out.println(string);
     }
     jedis.srem("orders","jd002");
     System.out.println(jedis.smembers("orders").size());
     //hash
     jedis.hset("hash1","userName","lisi");
     System.out.println(jedis.hget("hash1","userName"));
     Map<String,String> map = new HashMap<String,String>();
     map.put("telphone","13811814763");
     map.put("address","atguigu");
     map.put("email","abc@163.com");
     jedis.hmset("hash2",map);
     List<String> result = jedis.hmget("hash2", "telphone","email");
     for (String element : result) {
       System.out.println(element);
     }
     //zset
     jedis.zadd("zset01",60d,"v1");
     jedis.zadd("zset01",70d,"v2");
     jedis.zadd("zset01",80d,"v3");
     jedis.zadd("zset01",90d,"v4");
     
     Set<String> s1 = jedis.zrange("zset01",0,-1);
     for (Iterator iterator = s1.iterator(); iterator.hasNext();) {
       String string = (String) iterator.next();
       System.out.println(string);
     }         
  }
}

事务

    public boolean transMethod() throws InterruptedException {
	     Jedis jedis = new Jedis("127.0.0.1", 6379);
	     int balance;// 可用余额
	     int debt;// 欠额
	     int amtToSubtract = 10;// 实刷额度

	     jedis.watch("balance");
	     //jedis.set("balance","5");//此句不该出现,讲课方便。模拟其他程序已经修改了该条目
	     Thread.sleep(7000);
	     balance = Integer.parseInt(jedis.get("balance"));
	     if (balance < amtToSubtract) {
	       jedis.unwatch();
	       System.out.println("modify");
	       return false;
	     } else {
	       System.out.println("***********transaction");
	       Transaction transaction = jedis.multi();
	       transaction.decrBy("balance", amtToSubtract);
	       transaction.incrBy("debt", amtToSubtract);
	       transaction.exec();
	       balance = Integer.parseInt(jedis.get("balance"));
	       debt = Integer.parseInt(jedis.get("debt"));

	       System.out.println("*******" + balance);
	       System.out.println("*******" + debt);
	       return true;
	     }
	  }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值