ACID原则:
- 原子性(Atomicity):操作要么都成功,要么都不执行
- 一致性(Consistency):
即在事务开始之前和结束以后,数据库的完整性约束没有被破坏。
体现在两个层面:
1.数据库机制层面
数据库层面的一致性是,在一个事务执行之前和之后,数据会符合你设置的约束(唯一约束,外键约束,Check约束等)和触发器设置.这一点是由SQL SERVER进行保证的.
2.业务层面
对于业务层面来说,一致性是保持业务的一致性。这个业务一致性需要由开发人员进行保证。很多业务方面的一致性可以通过转移到数据库机制层面进行保证.比如,产品只有两个型号,则可以转移到使用CHECK约束使某一列必须只能存这两个型号. - 隔离性(Isolation):事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。在SQL标准中,定义了四个隔离级别:
- READ_UNCOMMITTED
- READ_COMMITTED
- REPEATABLE_READ
- SERIALIZABLE
https://www.cnblogs.com/wyaokai/p/10921323.html
来解决事务并发中带来的一下几个问题脏读(Dirty Read)、不可重复读(Non-repeatable Read)、幻读(Phantom Read)
不同的数据库或者说存储引擎默认支持不同的隔离级别,比如InnoDB存储引擎默认支持REPEATABLE_READ,而Mongodb只支持READ_UNCOMMITTED
事务的隔离级别:
https://blog.csdn.net/tolcf/article/details/49283575
隔离级别 |
脏读(Dirty Read) |
不可重复读(NonRepeatable Read) |
幻读(Phantom Read) |
未提交读(Read uncommitted) |
可能 |
可能 |
可能 |
已提交读(Read committed) |
不可能 |
可能 |
可能 |
可重复读(Repeatable read) |
不可能 |
不可能 |
可能 |
可串行化(SERIALIZABLE) |
不可能 |
不可能 |
不可能 |
一个可重复读中出现幻读的例子
https://www.zhihu.com/question/382393651
=========================================
分布式事务
分布式一致性协议之2PC和3PC
https://juejin.im/post/5cab6ff95188251af951c82b
https://www.bilibili.com/video/BV1at411y7iQ?from=search&seid=13774914441377346905
分布式事务综述:
https://www.cnblogs.com/xybaby/p/7465816.html
https://www.cnblogs.com/xybaby/p/7756163.html
分布式事务:分布式事务原理概述
https://yq.aliyun.com/articles/608863?spm=a2c4e.11153940.0.0.29fe22959WiLLB
TCC事务原理:https://yq.aliyun.com/articles/682871
分布式事务解决方案(2PC,3PC,CAP,柔性与刚性事物,LCN)
https://blog.csdn.net/gududedabai/article/details/82993594
常用的分布式事务解决方案
https://juejin.im/post/5aa3c7736fb9a028bb189bca
总结:
大多中小企业应该采用2PC或是MQ,因为使用TCC(Try-Confirm-Cancel)虽然相对比较完美,但从开发效率来讲太麻烦。每个逻辑块要拆分成3个接口来实现,都有预备阶段(比如库存不是直接扣减还是单独字段记录锁定库存)。
TCC框架:
tcc-transaction https://github.com/changmingxie/tcc-transaction
Hmily https://github.com/yu199195/hmily
ByteTCC https://github.com/liuyangming/ByteTCC
EasyTransaction https://github.com/liuyangming/ByteTCC
一站式分布式解决方案:
Fescar
Seata
LCN
所有支持2PC提交框架,原理大同小异。都引入了事务管理者和事务组的概念,通过对spring自身Connection实现代理,并接管本地事务的管理。本地事务执行完毕不再直接Commit而是会挂起等待事务管理者的通知。
1、本地事务开启并创建事务组并发送事务管理者,由事务管理者负责维护其组下各个事务并通知各个服务客户端是提交还是回滚。
2、调用下一个服务时会把事务组ID传递过去,被调用的服务会加入该事务组;创建本地事务加入事务组执行完毕后发送给事务管理者。
3、事务管理根据事务组里面的所有事务状态进行通知各个事务客户端。
其实使用MQ相对更简单,基于RabbitMq特性就可以很好地实现分布式事务,并且可以很容易地实现事务补偿机制。
通过发送方确认机制+失败回调;RabbitMq发送消息流程:发布消息---->交换机---->(队列是绑定到交换机上)队列,主要是这两个环节可能出错导致消息丢失。
通过发送方确认机制确保消息能够到达交换机上(其实也就是一个Broker上),然后通过失败回调确保交换机发送到队列上。
消费方确认模式:实例话一个监听器容器SimpleRabbitListenerContainerFactory,并且在容器里面指定消息确认为手动确认。消费方不管消费成功与否都需要确认,失败了可以指定回退消息或是废弃。
失败的话可以进入死信队列尝试补偿。