1、为什么会出现分布式事务
如果数据库是单台的,不会有分布式事务的问题,但是如果系统随着用户量的增加,不得已只能将用户信息分别保存在不同的数据库中,就只能使用分布式事务了。
2、分布式事务方案之两阶段提交(JTA: java transaction API ):
由于涉及到多个分布式的数据库,设置一个全局的事务管理器,来负责协调各个数据库的事务提交,为了实现分布式事务,设置两个阶段:
a、全局的事务管理器向各个数据库发出准备消息,各个数据库需要在本地把一切准备好,执行操作,锁住资源,记录redo/undo日志,但是并不提交,要进入一个时刻准备提交或回滚的状态,然后向全局事务管理器报告是否准备好了。
b、如果所有的数据库都报告准备好了,那全局事务管理器就下命令:提交,这个时候各个数据库才真正提交,由于之前已经准备好了,那么只需要快速完成本地提交即可。如果有任何一个数据库没有准备好,事务管理器就下命令:放弃,这时候各个数据库要执行回滚操作。并且释放各种在阶段1锁住的资源。
3、两阶段提交方案的漏洞:
任何地方都有失败的可能!比如在第二阶段,事务管理区出了问题怎么办?等等
而且,我个人觉得这个方案太过于复杂,使用门槛也高,想要普及怕是不容易。
4、最终一致性:消息队列
示例如下:假设两个账户(吕秀才和郭芙蓉)在两个独立的数据库中, 我们原来设计的JTA是要求从吕秀才账户减去100两银子, 然后在郭芙蓉账户加上100两银子
这个方案确实可以,但是也还存在另外一个问题,因为如上的事务,同时操作了数据库和消息队列,而数据库和消息队列是两个不同的组件,貌似无法保证事务的一致性。
然后有人提出了下面的方案(增加一张转账记录表)
后台有定时程序会定时运行,从时间表中取出记录,然后把这个记录写入到消息队列中,写入成功后,把记录的状态改为Done。
但是这样还是存在一个问题,如果定时程序成功的将事件记录写入到了消息队列中,而写入成功后突然断电,还没有将数据库中的记录修改为Done呢?这个该怎么办?
5、幂等性
幂等性就是为了解决上述说的,重复写入消息队列的问题。
先看看幂等性的定义:对一个事物操作的时候,可以一直重复的操作,那个事物不受影响!如果确实能实现幂等性,那么就算消息队列数据被重复写入了N次,还是一样的。
那么如何实现呢?
比如上述的情况,收账方每次收到前,也要有个表记录下收账记录(账单可能有个唯一ID),那么下次收到转账的时候,也需要判断下这个唯一ID是否已经转过了,如果有,那么就不收账就可以了。
(个人在工作中,由于公司的业务并没有涉及到转账这块,只是使用了消息队列来保证最终的一致性,虽然当时也考虑到了断电等情况,但是基于公司的实际情况,当时就没有再往下发散思维了。如果是那种涉及到钱的。确实,使用幂等性可以解决该问题!)