1. 事务描述

(1)什么是事务

  事务,就是把一堆事情绑在一起,按顺序的执行,都成功了才算完成,否则恢复之前的样子

  事务必须服从ACID原则,ACID原则分别是原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)

  原子性:操作这些指令时,要么全部执行成功,要么全部不执行。只要其中一个指令执行失败,所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态

  一致性:事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定

  隔离性:在该事务执行的过程中,无论发生的任何数据的改变都应该只存在于该事务之中,对外界不存在影响,只有在事务确认提交之后们才会显示该事务对数据的改变,其他事务才能获取到这些改变后的数据

  持久性:当事务正确完成后,它对于数据的改变是永久性的

(2)并发事务导致的常见错误

  第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖

  脏读:一个事务读取到另一个事务未提交的更新数据

  幻读也叫虚读:一个事务执行两次查询,第二次结果集包含第一次中没有或某些行已经被删除的数据,造成两次结果不一致,只是另一个事务在这两次查询中间插入或删除了数据造成的

  不可重复读:一个事务两次读取同一行的数据,结果得到不同状态的结果,中间正好另一个事务更新了该数据,两次结果相异,不可被信任

  第二类丢失更新:是不可重复读的特殊情况。如果两个事物都读取同一行,然后两个都进行写操作,并提交,第一个事物所做的改变就会丢失

2. redis事务处理

  redis事务通过MULTI、WATCH、UNWAYCH、EXEC、DISCARD五个命令实现

  MUTIL命令:用于开启一个事务,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行,它总是返回OK

  WATCH命令:对键进行监视,直到用户执行EXEC命令的这段时间里面,如果其他客户端抢先对任何被监视的键进行了替换、更新或删除等操作,那么当用户舱室执行EXEC命令的时候,事务将失败并返回一个错误(之后用户可以选择重试或者放弃事务)

  UNWATCH命令:在WATCH命令执行之后,EXEC命令执行之前对链接进行重置

  EXEC命令:执行事务命令

  DISCARD命令:客户端可以取消WATCH命令名清空所有已入队命令

3. redis事务示例

  下面将用商品交易示例说明事务处理过程

  

(1)将商品投放到市场

  a. 使用散列(users:)来管理市场中的所有用户信息,包括用户名、用户拥有的钱

  

  b. 使用集合(inventory:)来管理每个用户的所有商品信息,包括商品名名

  

  inventory:1对应用户User:1的报告

  c. 使用有序集合(market:)来管理投放到市场中的商品

  流程:检查inventory:1包裹中是否含有ItemL商品----->将inventory:1包裹中的ItemL商品添加到交易市场----->删除inventory:1包裹中的ItemL商品

def list_item(conn,userid,goodsname,price):#使用有序集合(market:)来管理投放到市场中的商品#商品的key为userid:goodsidinventory = 'inventory:%s' %(userid)user = 'User:%s' %(userid)goodsitem = '%s:%s' %(userid,goodsname)end = time.time() + 5pipe = conn.pipeline()while time.time() < end:try:pipe.watch(inventory) #监视包裹发生的变化if not pipe.sismember(inventory,goodsname):  #检查用户是否仍然持有将要被放入市场的商品pipe.unwatch()return Nonepipe.multi()pipe.zadd('market:',{goodsitem:price}) #将商品投放到市场pipe.srem(inventory, goodsname) #从用户包裹中删除该商品pipe.execute()print('商场中的商品:',conn.zrange('market:', 0, -1,withscores=True))print('商品投放市场后用户{}的商品:{}'.format(userid, conn.smembers(inventory)))return Trueexcept redis.exceptions.WatchError as e:print(e)return False

  测试:

  

(2)交易:User:2购买交易市场中的中的ItemL商品

  思想:使用watch对市场以及买家的个人信息进行监视,然后获取买家拥有的钱数以及商品市场的售价,并检查买家是否有足够的钱来购买商品,如果买家没有足够的钱,那么程序会取消事务,如果买家钱足够,那么程序首先会将买家支付的钱转移给卖家,然后将售出的商品移除商品交易市场。

def purchase_item(conn, buyerid, goodsname, sellerid):buyer = 'User:{}'.format(buyerid) #买家keyseller = 'User:{}'.format(sellerid) #卖家keybuy_inventory = 'inventory:{}'.format(buyerid)   #买家包裹keysell_inverntory = 'inventory:{}'.format(sellerid)   #卖家包裹keygoodsitem = '{}:{}'.format(sellerid,goodsname)  #市场中的商品keyend = time.time() + 5pipe = conn.pipeline()while time.time() < end:try:pipe.watch('market:',buyer)  #对商品买卖市场以及买家的个人信息进行监视funds = int(pipe.hget(buyer,'funds'))  #得到买家拥有的钱print('买家手上的钱:', funds)price = pipe.zscore('market:', goodsitem)  #得到商品的价格print('price:',price)  if funds < price:pipe.unwatch()return Nonepipe.multi()pipe.hincrby(buyer, 'funds', int(-price))  #买家的钱减少pipe.hincrby(seller, 'funds', int(price))  #卖家的钱增加pipe.sadd(buy_inventory,goodsname)pipe.zrem('market:', goodsitem)pipe.execute()print('交易市场中的商品:', conn.zrange('market:', 0, -1, withscores=True))print('买家现在手中的钱:',conn.hget(buyer, 'funds'))print('买家包裹内容:', conn.smembers(buy_inventory))print('卖家现在手中的钱:',conn.hget(seller, 'funds'))return Trueexcept redis.exceptions.WatchError as e:print(e)return False

  测试:

if __name__ == '__main__':conn = redis.Redis()#create_users(conn)#create_user_inventory(conn)list_item(conn,1,'ItemL',28)purchase_item(conn, 2, 'ItemL', 1)

4. redis持久化

  redis提供了两种不同的持久化方式来将数据从内存存储到硬盘里面,一种是RDB持久化,原理是将redis内存中的数据库记录定时dump到磁盘上的RDB持久化,另外一种是AOF(append only file)持久化,原理是被执行的写命令复制到磁盘里。

(1)RDB持久化配置

# Save the DB on disk:
#  设置sedis进行数据库镜像的频率。
#  900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化)。
#  300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化)。
#  60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)。
save 900 1
save 300 10
save 60 10000stop-writes-on-bgsave-error yes
# 在进行镜像备份时,是否进行压缩。yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁盘空间。
rdbcompression yes
# 一个CRC64的校验就被放在了文件末尾,当存储或者加载rbd文件的时候会有一个10%左右的性能下降,为了达到性能的最大化,你可以关掉这个配置项。
rdbchecksum yes
# 快照的文件名
dbfilename dump.rdb
# 存放快照的目录
dir ./

(2)创建快照的方法

  a. 客户端可以通过想redis发送besave命令来创建一个快照,对于支持bgsave命令的平台来说(基本上所有平台都支持,除了windows平台),redis会调用fork来创建一个子进程,然后子进程负责将快照写入磁盘,而父进程继续处理命令请求

  b. 客户端还可以向redis发送save命令来创建一个快照,接到save命令的redis服务器在快照创建完毕之前不再响应任何其他命令,save命令不常用,我们通常只会在没有足够内存去支持bgsave的情况下,又或者即使等待持久化操作执行完毕也无所谓的情况下,才会使用这个命令

  c. 当redis通过shutdown命令接收到关闭服务器请求时,或者接收到标准term命令时,会执行一个save命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在save命令执行完毕之后关闭服务器

  d. 当一个redis服务器链接另一个redis服务器,并向对方发送sync同步命令来开始一次复制操作时,如果主服务器目前没有执行bgsave操作,或者主服务器并非刚刚执行完bgsave操作,那么主服务器就会执行bgsave

(3)AOF持久化配置

# 是否开启AOF,默认关闭(no)
appendonly yes
# 指定 AOF 文件名
appendfilename appendonly.aof
# Redis支持三种不同的刷写模式:
# appendfsync always #每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用。
appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,是受推荐的方式。
# appendfsync no     #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不被推荐。#在日志重写时,不进行命令追加操作,而只是将其放在缓冲区里,避免与命令的追加造成DISK IO上的冲突。
#设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes
no-appendfsync-on-rewrite yes
#当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。
auto-aof-rewrite-percentage 100
#当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。
auto-aof-rewrite-min-size 64mb

(4)AOF重写原理

  AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:

  a. Redis 执行 fork() ,现在同时拥有父进程和子进程

  b. 子进程开始将新 AOF 文件的内容写入到临时文件

  c . 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的

  d. 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾

  注意:在将内存缓存中的数据追加到新AOF文件末尾和rename时,主进程是阻塞的

 

 

转载于:https://www.cnblogs.com/xiaobingqianrui/p/10094845.html

redis实战之事务与持久化相关推荐

  1. redis 事务,持久化,日志,主从,VM

    redis目前对事务的支持比较简单,只能保证一个客户端连接发起事务中的命令可以连续执行,而中间不会插入其他客户端的命令. 1.事务 一般情况下,redis接收到一个客户端发送的命令,立刻执行并返回结果 ...

  2. Redis全部知识总结(概念、安装、用法、数据类型、事务、持久化、Jeids、订阅系统、缓存穿透及雪崩等)

    Redis NoSql简述 Nosql概念 Nosql的四大分类 Redis概述 Redis的安装 安装文件 Window下安装 Linux下安装 redis-benchmark 压力测试工具 五大数 ...

  3. 尚硅谷Redis尚硅谷学习汇总_事务_持久化_主从复制_集群_穿透_雪崩_击穿

    前言 该文章是我在学习Redis过程中写的学习汇总,包括了基本使用和常用命令.RDB和AOF.配置文件.事务.击穿.穿透.雪崩.集群等,都记录了详细过程,不管是新手学习还是有基础的同学拿来回顾都是可以 ...

  4. Redis事务、持久化、主从复制、哨兵、JRedis和JRedis Pool(摘抄)

    事务是指一系列操作步骤,这一系列的操作步骤,要么完全执行,要么完全地不执行 Redis中的事务是一组命令的集合,至少是两个或两个以上的命令,redis事务保证这些命令被执行时中间不会被任何操作打断 ( ...

  5. Redis实战(五):Redis的持久化RDB、fork、copyonwrite、AOF、RDBAOF混合使用

    补充一个知识 缓存:数据可以丢,保证速度. 数据库:数据是绝对不能丢的,保证速度+持久性,内存中的数据是掉电易失的. 存储层: 快照/副本 日志文件 $$优先级高于管道 fork() fork是系统调 ...

  6. Redis实战(11)高级特性(3)持久化

    redis 是一个支持持久化的内存数据库,也就是说redis 需要经常将内存中的数据同步到磁盘 来保证持久化.redis 支持两种持久化方式,一种是Snapshotting(快照)也是默认方式,另 一 ...

  7. Redis实战和核心原理详解(8)使用快照RDB和AOF将Redis数据持久化到硬盘中

    一.前言 我们知道Redis是一款内存服务器,就算我们对自己的服务器足够的信任,不会出现任何软件或者硬件的故障,但也会有可能出现突然断电等情况,造成Redis服务器中的数据失效.因此,我们需要向传统的 ...

  8. Redis实战 - 15 Redis事务机制和乐观锁实现

    文章目录 1. Redis事务简介 2. Redis事务的操作命令 3. Redis的事务回滚 4. Redis监控事务 1. Redis事务简介 在 Redis 中,也存在多个客户端同时向 Redi ...

  9. Redis 实战笔记

    Redis yum源安装 yum install -y epel-release redis systemctl enable redis systemctl start redis systemct ...

  10. 最新微服务、MySQL、Nginx加Redis实战,助你成功向阿里P8进军!

    前言 当下互联网时代,国际社会发展迅速,技术革新更加迅猛.未来智能时代,是一个数据时代,而如何处理好这些数据,就是科技发展的趋势. 本文主要为大家介绍一些2020年阿里P8对标学习教程,涵盖微服务架构 ...

最新文章

  1. 微软将花25亿美元建其最大数据中心
  2. 通信测试:5G 时代的“卖水人”
  3. python easygui_EasyGUI是python的一个超级简单的GUI工具介绍(一)
  4. python简单代码 春节集五福-新年福利来一波之Python轻松集齐五福(demo)
  5. Oracle左右全连接总结
  6. USTC服务器使用笔记
  7. 点击表格获取列索引的方法
  8. 微信小程序_wxml学习
  9. VTK:科赫雪花用法实战
  10. 从 FFmpeg 性能加速到端云一体媒体系统优化
  11. CF653F. Paper task
  12. html网页中使用mock,关于Mock.js使用
  13. python中‘/’和‘//’区别
  14. Java中布尔值的定义_使用简单的布尔值作为自定义验证器
  15. perl中DBD-oracle安装,Linux下安装perl的DBI和DBD
  16. Troubleshooting OpenStack 瘫痪 - 每天5分钟玩转 OpenStack(160)
  17. 开源linux 二进制工具,谷歌开源二进制文件对比工具 BinDiff
  18. Oracle数据库对象 序列
  19. Understand Rails Authenticity Token
  20. python 保存bin文件,python bin文件处理

热门文章

  1. MAC编译freetype
  2. JS中字串转参数用的false/true
  3. 成功的人不是最聪明的那个人,但绝对是一个交流很棒的人
  4. OpenCV绘制半透明效果的代码
  5. 管理感悟:遇到问题,使用矩阵测试法
  6. 管理感悟:鼓励正确的山头主义
  7. 为什么每个人都有发旋?
  8. 特殊的栈GetMin
  9. 【淘坏菌】Markdown 积累
  10. Dxg——Bat批处理 开发笔记整理分类合集【所有的相关记录,都整理在此】