大家好,我是冰河~~
今天,咱们就暂时不聊【精通高并发系列】了,今天插播一下分布式事务,为啥?因为冰河联合猫大人共同创作的分布式事务领域的开山之作——《深入理解分布式事务:原理与实战》一书正式出版了,于2021年10月20日开始在当当预售,当天即登上当当新书榜第一的位置!
划重点:当当10.20~10.24限时5折优惠!!打开当当首页,搜索:分布式事务,找到5折优惠商品链接,点击加购,下单即可。
本地事务 本地事务流程在介绍分布式事务之前,我们先来看看本地事务。首先,我们先来一张图。
由上图,我们可以看出,本地事务由资源管理器(比如DBMS,数据库管理系统)在本地进行管理。
本地事务的优缺点本地事务具备相应的优点,也有其不足。
优点:
支持严格的ACID属性。
可靠,事务实现的效率高(只是在本地操作)。
可以只在RM(资源管理器)中操作事务。
编程模型简单。
缺点:
缺乏分布式事务的处理能力。
数据隔离的最小单元由RM(资源管理器决定),开发人员无法决定数据隔离的最小单元。比如:数据库中的一条记录等。
ACID属性说起事务,我们不得不提的就是事务的ACID属性。
A(Atomic):原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失
败的情况。
C(Consistency):一致性,在事务执行前后,数据库的一致性约束没有被破坏。比如:张三向李四转100元,
转账前和转账后的数据的正确状态叫作一致性,如果出现张三转出100元,李四账户没有增加100元这就出现了数
据错误,就没有达到一致性。
I(Isolation):隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事
务不能看到其他事务运行过程的中间状态。通过配置事务隔离级别可以避脏读、重复读等问题。
D(Durability):持久性,事务完成之后,该事务对数据的更改会被持久化到数据库,且不会被回滚。
分布式事务随着业务的快速发展,网站系统往往由单体架构逐渐演变为分布式、微服务架构,而对于数据库则由单机数据库架构向分布式数据库架构转变。此时,我们会将一个大的应用系统拆分为多个可以独立部署的应用服务,需要各个服务之间进行远程协作才能完成事务操作。
我们可以使用下图来表示刚开始我们系统的单体架构。
上图中,我们将同一个项目中的不同模块组织成不同的包来进行管理,所有的程序代码仍然是放在同一个项目中。
后续由于业务的发展,我们将其扩展为分布式、微服务架构。此时,我们将一个大的项目拆分为一个个小的可以独立部署的微服务,每个微服务都有自己的数据库,如下所示。
又比如,在我们的程序中,经常会在同一个事务中执行类似如下的代码来完成我们的需求。
@Transactional(rollbackFor = Exception.class) public void submitOrder() { orderDao.update(); // 更新订单信息 accountService.update(); // 修改资金账户的金额 pointService.update(); // 修改积分 accountingService.insert(); // 插入交易流水 merchantNotifyService.notify(); // 通知支付结果 }上述代码中的业务,仅仅在submitOrder()方法上添加了一个@Transactional注解,这能够在分布式场景下避免分布式事务的问题吗?很显然是不行的。
如果上述代码所对应的:订单信息、资金账户信息、积分信息、交易流水等信息分别存储在不同的数据里,而支付完成后,通知的目标系统的数据同样是存储在不同的数据库中。此时就会产生分布式事务问题。
分布式事务产生的场景 跨JVM进程当我们将单体项目拆分为分布式、微服务项目之后,各个服务之间通过远程REST或者RPC调用来协同完成业务操作。典型的场景就是:商城系统中的订单微服务和库存微服务,用户在下单时会访问订单微服务,订单微服务在生成订单记录时,会调用库存微服务来扣减库存。各个微服务是部署在不同的JVM进程中的,此时,就会产生因跨JVM进程而导致的分布式事务问题。
跨数据库实例