当前位置: 首页 > news >正文

网站建设项目教程广州花都网站开发

网站建设项目教程,广州花都网站开发,贵州建设厅网站建筑企业公示栏,福州网站开发培训Redis事务与MySQL事务 不一样。原子性:MySQL有Undo Log机制,支持强原子性,和回滚。Redis只能保证事务内指令可以不被干扰的在同一批次执行,且没有机制保证全部成功则提交,部分失败则回滚。隔离性:MySQL的隔…

Redis事务与MySQL事务

  • 不一样。
  • 原子性:MySQL有Undo Log机制,支持强原子性,和回滚。Redis只能保证事务内指令可以不被干扰的在同一批次执行,且没有机制保证全部成功则提交,部分失败则回滚。
  • 隔离性:MySQL的隔离性指多个事务可以并发执行,MySQL有MVCC机制。而Redis没有,Redis是事务提交前的指令不会被执行,单线程的环境下,也就不存在事务未提交时,事务内外数据不一致的隔离性问题了。
  • 持久性:MySQL事务先写Undo Log,并有Redo Log的两阶段提交机制,可以保证持久性。但是Redis持久化机制只有RDB和AOF持久化策略,若事务成功执行且数据刚好被保存,则可以满足持久性。
  • 一致性:MySQL是指数据库从一个合法(指符合业务预期)状态转换成另一个合法状态,这种只要Redis执行不出错,可以保证。

Redis事务

  • 官方文档:https://redis.io/docs/latest/develop/interact/transactions/
  • 极简概括:将一批要执行的Redis指令,放入Redis的执行队列中,事务执行时(不包含事务未提交时) 使其不被并发过来的任务干扰执行。(无法做到严格意义上的ACID 4特性)。
  • 适用场景:
    • 性能优化:10条命令传输10次执行10次,与1次批量执行10条命令,性能有差异。
    • 乐观锁实现:结合Watch可以实现乐观锁。
  • 优点:如上的应用场景就是优点。
  • 缺点:无法像MySQL那样保证原子性、持久性。
  • 关键字:mutli(开启事务),discard(停止事务)、exec(执行事务)、watch(监视指定key)、unwatch(取消监视所有key)。

事务操作实操

测试multi与exec,常规执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a a
QUEUED
127.0.0.1:6379> set b b
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK

测试discard,事务未提交,强行终止,则修改不会生效

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a a1
QUEUED
127.0.0.1:6379> set b b1
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get a
"a"
127.0.0.1:6379> get b
"b"

Redis事务异常(语法错误导致整个事务执行失败,非回滚操作)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a a2
QUEUED
127.0.0.1:6379> sset b b2
(error) ERR unknown command `sset`, with args beginning with: `b`, `b2`, 
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get a
"a"
127.0.0.1:6379> get b
"b"

Redis事务异常(非语法错误引起的部分失败,无法保证ACID中的A,无回滚机制)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a aa
QUEUED
127.0.0.1:6379> incr a
QUEUED
127.0.0.1:6379> set b bb
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
127.0.0.1:6379> get a
"aa"
127.0.0.1:6379> get b
"bb"

有Redis事务,为什么又出来了Lua?

  • Redis事务和Lua机制并不冲突,并且要比Redis事务更加强大。
  • 应对并发安全问题:虽然有了Lua的加持,仍不支持事务回滚或者,强原子性(要么都成功,要么都回滚),但是Lua可以保证当前的操作不被打断(无间隙执行),应对并发(例如超卖)问题,Lua能妥善解决。
  • Redis事务不支持流程控制,只支持函数调用:配合Lua用于实现无间隙执行的复杂逻辑,这样的用法非常多。因为高并发下,若单纯利用编程语言多次调Redis,实现判断或循环逻辑,这中间有间隙,会有并发问题发生。
    Lua是一门高性能脚本语言,Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译、运行。Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。

关于Redis+Lua是否是原子性执行的争议问题

https://redis.io/docs/latest/develop/interact/programmability/eval-intro/
对Redis官网进行搜索,出现了原子性的字眼。
原话是:
Blocking semantics that ensure the script’s atomic execution.
Lua lets you run part of your application logic inside Redis. Such scripts can perform conditional updates across multiple keys, possibly combining several different data types atomically.

但是我想了想有矛盾的地方:
MySQL使用了undo log来保证原子性,要么成功全部执行,要么失败全部回滚。
众所周知,Redis不支持回滚的,那么ACID的A就没办法全部保证,最多是没有执行期间没有间隙,不被其它过来的请求影响,引起并发问题。

然后我又看了看阿里某架构师对此的剖析,跟我设想的一样:
Redis会把Lua脚本当做一个整体去执行,中间不会被其它的命令插入,但是如果执行过程中出现了错误,事务是不会回滚的。
也就意味着执行Lua脚本的过程不可被拆分,不可被中断,但是遇到错误不会回滚。

Redis乐观锁

  • 悲观锁:很悲观,认为数据大概率会有并发一致性问题,首次请求过来时加具有互斥性的锁阻塞其它并发请求,但是Redis是高性能组件,阻塞会带来性能问题,所以不用悲观锁。
  • 乐观锁:乐观,认为数据小概率有并发一致性问题,所以读数据时不上锁,但是写数据时,会判断一下这个数据是否被改动,从而在旧值的基础上做修改,如果数据被改动,则失败掉此次执行。
  • 注意:redis在事务exec或者discard,都会取消对key的watch操作。
  • 解决问题:高并发读多写少场景下Redis数据一致性问题。
  • 演变:

假设用户a账户有100元,此时要添加10元

127.0.0.1:6379> set a_money 100
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby a_money 10
QUEUED
127.0.0.1:6379> exec
1) (integer) 110
127.0.0.1:6379> get a_money
"110"

假设用户a账户有110元,此时要添加20元,但是事务未提交期间,已经被其它请求改为了115,然后事务内加了20。
由于是加法,所以值正确,但是事务内的数据一般是不让改的,很多情况下的自增或者自减,是需要以原数据为基础基础为准的(这也是MySQL隔离级别的用意,所以有了当前读和快照读的区分)。

终端1
127.0.0.1:6379> get a_money
"110"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby a_money 20
QUEUED终端2
127.0.0.1:6379> get a_money
"110"
127.0.0.1:6379> incrby a_money 5
(integer) 115终端1
127.0.0.1:6379> get a_money
"110"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby a_money 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 135
127.0.0.1:6379> get a_money
"135"

Redis没有事务的隔离机制怎么办?使用watch加锁。

终端一
127.0.0.1:6379> watch a_money
OK
127.0.0.1:6379> get a_money
"135"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby a_money 20
QUEUED终端二模拟其它并发用户
127.0.0.1:6379> incrby a_money 5
(integer) 140终端1
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get a_money
"140"
事务没有成功被执行,因为watch监控了a_money的值,一旦事务执行期间,被事务外的请求锁修改,则失败掉此次事务。
乐观锁,在此处的体现就是,利用watch监控一下事务执行期间,a_money的值是否被改动。

unwatch 使用

终端1
127.0.0.1:6379> set a a
OK
127.0.0.1:6379> watch a
OK
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a a1终端2,模拟并发过来的用户请求
127.0.0.1:6379> set a a2
OK终端1,执行unwatch后,取消了对所有key的监控,执行exec时,就不是nil了。
127.0.0.1:6379> exec
1) OK
127.0.0.1:6379> get a
"a1

watch部分key,其余key的反应

终端1
127.0.0.1:6379> set a a
OK
127.0.0.1:6379> set b b
OK
127.0.0.1:6379> watch a
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a a1
QUEUED
127.0.0.1:6379> set b b1
QUEUED终端2
127.0.0.1:6379> set a a2
OK
127.0.0.1:6379> set b b2
OK终端1,watch a,没有watch b,事务提交时,被watch的key,可以影响没有被watch的key。
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get a
"a2"
127.0.0.1:6379> get b
"b2"

管道

  • 官方文档:https://redis.io/docs/latest/develop/use/pipelining/
  • 极简概括:将多个指令的操作,一次性发送给Redis,进行批量处理。
  • 解决问题:减少网络开销,减少频繁接收命令的开销(10轮request->exec->response,精简为1次request->10次exec->1次response),避免多条Redis指令通信往返时间。避免Redis服务器频繁的从用户态到内核态的调用,减少上下文通信时间。
  • 与事务对比:批量处理指令的行为,类似事务。
  • 注意:redis-cli会话内部并未提供管道命令,(但是使用Linux Shell端支持STDIN标准输入到redis-cli实现管道,例如echo -e "set a aa \n set b bb" | redis-cli --pipe),但redis-server提供了这个机制,管道机制最好用编程语言的客户端演示。
若在redis-cli会话内部实现管道,会有如下提示:
127.0.0.1:6379> pipe
(error) ERR unknown command `pipe`, with args beginning with: 
127.0.0.1:6379> pipeline
(error) ERR unknown command `pipeline`, with args beginning with:
  • PHP实现:
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);$pipe = $redis->pipeline();$pipe->set('key1', 'value1');
$pipe->set('key2', 'value2');
$pipe->get('key1');
$pipe->get('key2');$responses = $pipe->exec();var_dump($responses);$redis->close();返回执行的结果
array(4) {[0]=>bool(true)[1]=>bool(true)[2]=>string(6) "value1"[3]=>string(6) "value2"
}

管道异常情况(Redis语法错误)

以PHP为例,经实际测试(set函数缺少参数2),Redis调用语法错误(非PHP语法错误),会升级为PHP出现致命错误,管道流程走不下去。

Fatal error: Uncaught ArgumentCountError: Redis::set() expects at least 2 arguments, 1 given in E:\Host\test\t1.php:7
Stack trace:
#0 E:\Host\test\t1.php(7): Redis->set('a')
#1 {main}thrown in E:\Host\test\t1.php on line 7

管道异常情况(Redis执行异常)

经过实测,对字符串进行递增操作,除了incr返回false外,其余上下文代码执行不受影响。

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);$pipe = $redis->pipeline();$pipe->set('a', 'a');
$pipe->incr('a');
$pipe->set('b', 'b');
$pipe->get('a');
$pipe->get('b');$responses = $pipe->exec();var_dump($responses);$redis->close();array(5) {     [0]=>        bool(true)[1]=>bool(false)[2]=>bool(true)[3]=>string(1) "a"[4]=>string(1) "b"
}
http://www.yayakq.cn/news/550131/

相关文章:

  • 做网站上传的图片大小wordpress自定义评论样式
  • 网站运营阶段头像设计
  • 沈阳城市建设学院官方网站网站做跳转微信打开
  • 上海专业的网站公阅读分享网站模板
  • 五大搜索引擎 三大门户网站营销型网站的目标是
  • 戴尔网站建设目标中山移动网站建设公司
  • 银川做网站最好的公司有哪些西安游玩攻略
  • 某品牌休闲零食网站建设规划书网站开发目标开题报告
  • wordpress多站点命名网站开发与维护项目招标
  • 怎么做网站推广怎么样网站推广seo设置
  • 淄博乐达网站建设内部优惠券网站怎么做
  • 友汇网站建设管理后台东莞网站开发前三强
  • 网站更换建设网站书籍
  • 程序员网站建设北京网站设计定制开发建设公司
  • 贵州省建设网官方网站办公管理系统有哪些
  • 贵阳网站建设贵阳做模具行业的网站
  • python 快速做网站目前最主流的网页制作软件是
  • 网站里的友情链接网站开发的技术路线是什么
  • wordpress 多站点 插件石景山网站制作
  • 做外贸没有网站需要什么条件做worksheet的网站
  • 做浏览单的网站有哪些seo优化及推广如何运营
  • 长春哪有做网站公司做家常便饭网站
  • 石大网页设计与网站建设客观题画册设计及制作
  • 南宁手机建站模板做网站可以挣钱吗
  • 网站制作企业一流的中小型网站建设
  • 美丽女性网-大型女性门户网大型程序700m网站程序源码织梦网站开发 海淀
  • 全屏网站模板如何阿里网站建设
  • 网站排名下降的原因深圳地铁公司网站
  • vi设计包含什么网站优化公司电话
  • 无锡网站制作那些公众号设计平台