西安网站建设 企业建站,饭店装修设计,给关亨做网站的设计公司,网页游戏排行榜前十名知乎1 复习下何为事务机制#xff1f;
Transaction#xff08;事务#xff09;是计算机的特有术语#xff0c;它一般指单个逻辑工作单位#xff0c;由一系列的操作组合而成#xff0c;在这些操作执行的时候#xff0c;要么都执行成功#xff0c;要么都不执行#xff0c;防…1 复习下何为事务机制
Transaction事务是计算机的特有术语它一般指单个逻辑工作单位由一系列的操作组合而成在这些操作执行的时候要么都执行成功要么都不执行防止数据结果的不一致性。 简而言之事务是一个不可分割的工作逻辑单位。为了衡量工作单元是否具备事务能力需要满足四个特征ACID即 原子性Atomicity或称不可分割性、一致性Consistency、隔离性Isolation又称独立性、持久性Durability。
原子性Atomicity一个事务transaction中的所有操作要么全部完成要么全部不完成不会结束在中间某个环节。事务在执行过程中发生错误会被回滚Rollback到事务开始前的状态就像这个事务从来没有执行过一样。一致性Consistency在事务开始之前和事务结束以后数据库的完整性没有被破坏。这表示写入的数据必须完全符合所有的预设规则这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。 实体完整性存在唯一的主键列完整性:字段类型、字段长度等符合所有的预设规则foreign key 外键约束用户自定义完整性如用户购物支付前后商家收入和用户的余额总和不变隔离性Isolation数据库允许多个并发事务同时对其数据进行读写和修改的能力隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别包括读未提交read uncommitted、读提交read committed、可重复读repeatable read和串行化Serializable。持久性Durability事务处理结束后对数据的修改就是永久的会持久化到硬盘上即便系统故障也不会丢失。
2 Redis模式下如何实现事务机制
Redis 支持事务机制他实现事务的关键命令包括
MULTI、EXEC、DISCARD 、 WATCHMULTI 开启事务总是返回OKEXEC 提交事务DISCARD 放弃事务即放弃提交执行WATCH 监控QUEUED 命令加入执行的队列没操作一个动作的时候都先加入Queue
根据上述命令Redis 事务的执行过程包含三个步骤
开启事务MULTI命令入队QUEUE执行事务或丢弃EXEC 或者 DISCARD
2.1 显式开启一个事务
Client 通过 MULTI 命令显式开启一个事务随后执行的操作将会暂时缓存在Queue中实际并没有立即执行。
2.2 将命令入队列Queue
Client 端 把事务中的要执行的一系列操作指令发送到Service 端。 Redis服务端 实例接收到指令之后并不是马上执行而是暂存在命令队列中。
2.3 执行事务或丢弃
当Client端向Service端发送的命令都Ready了之后可以发送提交执行或者丢弃事务的命令如果是执行则操作队列中的具体指令如果是丢弃则是清空队列命令。
EXEC执行队列中的指令DISCARD丢弃保存在队列中的命令
2.4 EXEC命令执行示例
通过 MULTI 和 EXEC 执行一个事务过程
#开启事务MULTI
OK
# 定义一系列指令set name brand
QUEUEDset age 18
QUEUEDINCR age
QUEUEDGET name
QUEUEDGET age
QUEUED
# 实际执行事务EXEC
# 获取执行结果
1) OK
2) OK
3) 19
4) brand
5) 19
从上面可以看出来每个读写指令执行后的返回结果都是 QUEUED代表这些操作只是暂存在指令队列中并没有实际执行。 当发送了 EXEC 命令之后才真正执行并获取结果。
2.5 DISCARD命令放弃事务
通过 MULTI 和 DISCARD 丢弃执行清空指令队列
# 初始化订数据SET name brand
OKSET age 18
OK
# 开启事务MULTI
OK
# 数据增量1INCR age
QUEUED
# 丢弃DISCARD
OK
# 执行结果是增量前的数据get age
182.6 因为命令错误导致的事务回滚
体现原子性再发生故障的时候要么执行都成功要么执行都失败
# 开启事务MULTI
OK
# 初始一个数据SET age 18
OK
# 对该数据进行更新但Redis不支持该命令返回报错信息UPD age 17
(error) ERR unknown command UPD, with args beginning with: age, 17,
# 继续发送一个指令 降低age的值该指令是正确的DECR age
QUEUED
# 执行exec但是之前有错误所以Redis放弃了事务不再执行EXEC
(error) EXECABORT Transaction discarded because of previous errors.3 Redis事务机制能实现哪些属性
类似MySQL的事务Redis 事务一次性可以执行多个指令 而这多个指令通过以下的方式来保证
EXEC 命令执行之前所有的指令都是被暂存Queued在队列中Service端接收到EXEC命令后开始执行事务事务中某些命令执行失败其余命令依旧执行在事务执行的时候具备隔离性其他Client端执行的指令不会乱入到当前指令的执行顺序中的。
3.1 原子性Atomicity
在事务执行的过程中可能遇到这几种命令执行错误
在执行 EXEC 命令前指令本身错误 参数数量不一致构成的错误命令名称构成的错误使用了不存在或者错误的命令比如上面的 UPD超过MaxMemory内存限制导致内存不足在执行 EXEC 命令后命令的不合理操作导致的失败。比如数据类型不匹配对 String 类型 的 value 执行了 INCR 或者 DECR 之类的操作在执行事务的 EXEC 命令时实例故障导致的失败这种情况比较少一点。
3.1.1 EXEC 执行前报错
执行前错误是指命令入队Queue时Redis 就会发现并记录报错。 即使执行了 EXEC命令之后Redis也会拒绝执行指令队列中的所有指令返回事务失败的结果。 这样一来所有的指令都不会被执行保持了原子性。下面是指令入队列的报错的实例跟上面的举例一致
# 开启事务MULTI
OK
# 初始一个数据SET age 18
OK
# 对该数据进行更新但Redis不支持该命令返回报错信息UPD age 17
(error) ERR unknown command UPD, with args beginning with: age, 17,
# 继续发送一个指令 降低age的值该指令是正确的DECR age
QUEUED
# 执行exec但是之前有错误所以Redis放弃了事务不再执行EXEC
(error) EXECABORT Transaction discarded because of previous errors.3.1.2 EXEC 执行后报错
这个跟上面的情况正好相反指令入Queue时命令的类型虽然不匹配但是并没有在预编译的时候检查出。 只有在EXEC 命令之后实际执行指令的时候才会报错。其他正确的指令还是会执行成功不保证原子性。 参考下面
# 开启事务MULTI
OKset age 18
QUEUEDset name brand
QUEUEDINCR age
QUEUED
# 这边对String类型进行DECR没有报错但是在执行指令的时候会报错误DECR name
QUEUED
# 执行会发现其他三条执行执行成功只有一条执行失败返回报错信息EXEC
1) OK
2) OK
3) 19
4) ERR value is not an integer or out of range
# 查看结果get name
brandget age
193.1.3 在EXEC执行时发生实例故障
可以使用AOF日志把未完成的事务操作从AOF日志中去除之后使用AOF进行恢复时就不会被再次执行以此保证整个操作的原子性。 这个需要Redis启用AOF日志这个持久化能力。
3.1.4 对于上述几种错误特征的总结
指令入队列时有报错所有指令中只要有一条不是QUEUED就会放弃事务执行保证原子性。如 3.1.1指令入队列时没报错所有指令都是QUEUED但在实际执行EXEC时报错则不保证原子性。如 3.1.2EXEC执行时出现故障如果开启了 AOF 日志可以保证原子性。如 3.1.3
3.2 一致性
跟原子性类似一致性会受到错误指令、执行异常、Redis故障等情况的影响主要有如下几种情况
指令入队列时有报错事务被放弃执行所以可以保证一致性。指令入队列时正产实际执行EXEC时报错则是错误部分不会执行正确指令依旧正常执行也可以保证一致性。Redis实例故障分成几种 未开启持久化情况故障重启后数据都清空结果是一致的。RDB快照事务命令操作的结果不被保存到 RDB 快照中所以在恢复时数据结果是一致的。AOF 日志发生故障时使用 redis-check-aof 清除事务中对应操作数据库恢复后也保持一致。
3.3 隔离性
从隔离性这个角度事务执行的时机可以分成两种
一种是操作在EXEC执行之前纯入队期间这时候采用 WATCH 的机制来保障另一种是开始执行EXEC之后实际开始执行命令了这时候本身具备隔离性了。
3.3.1 WATCH监测对象是否有变化
如果前后有变化说明被修改了这时就放弃事务执行避免事务的隔离性被破坏。 3.3.2 对操作进行顺序并发操作排在 EXEC 之后
Redis 操作命令是单线程执行的所以在EXEC 命令执行后不会乱入其他操作Redis 会保证把指令队列中的所有指令都操作完成之后。 在执行后续的命令所以这种模式并发操作不会破坏事务的隔离性。它具有天然的隔离能力。 3.4 持久性
因为Redis的持久化特性所以有如下三种可能性
未开启 RDB快照 或 AOF日志事务肯定不具备持久化能力。RDB快照模式我们在Redis持久化那一篇中聊过RDB具有快照间隙事务执行在快照之间则不会被保障。AOF日志无论日志持久化选项是 no、everysec 和 always 都会存在数据丢失的情况所以也是无法完全保障的。 所以不管 Redis 采用什么持久化模式事务的持久性属性是得不到完全保证的。
4 总结
Redis 具备了一定的原子性但不支持回滚。DISCARD 主要负责清空指令列表放弃操作。Redis 具备一致性的能力Redis 具备隔离性的能力Redis 无法保证持久性