目录
1.本地事务
Connection conn = ... //获取数据库连接
conn.setAutoCommit(false); //开启事务
try{
//...执行增删改查sql
conn.commit(); //提交事务
}catch (Exception e) {
conn.rollback();//事务回滚
}finally{
conn.close();//关闭链接
}
spring 提供了事务功能
-
配置事务管理器。spring提供了一个PlatformTransactionManager接口,其有2个重要的实现类: DataSourceTransactionManager:用于支持本地事务,事实上,其内部也是通过操作java.sql.Connection来开启、提交和回滚事务。
JtaTransactionManager:用于支持分布式事务,其实现了JTA规范,使用XA协议进行两阶段提交。需要注意的是,这只是一个代理,我们需要为其提供一个JTA provider,一般是Java EE容器提供的事务协调器(Java EE server's transaction coordinator),也可以不依赖容器,配置一个本地的JTA provider。
-
在需要开启的事务的bean的方法上添加@Transitional注解
2.分布式事务场景
随着SOA和数据库的拆分,完成一个业务功能可能需要横跨多个服务,操作多个数据库,所以就涉及到了分布式事务:保证对于多个资源服务器的数据操作,要么全部成功,要么全部失败。分布式事务是为了保证不同资源服务器的数据一致性。比如下单操作: 库存系统-扣库存;订单系统-更新状态
1. 跨库事务
一个业务功能需要操作多个库
2. 分库分表
3.服务化
所以,分布式场景中,无一例外的都直接或间接的操作了多个数据库。
3.两阶段提交 & 三阶段提交 & paxos
CAP + BASE
柔性事务BASE
-
基本可用(Basically Available)
指分布式系统在出现不可预知故障的时候,允许损失部分可用性。
-
软状态( Soft State)
指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性。
-
最终一致( Eventual Consistency)
强调的是所有的数据更新操作,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
CAP原理
- Consistency:持久性存储+备份
- Availibility:可用性(切换)
- Partition Tolerance:数据一致性。网站规模总是快速扩张,所以P是必须的
两阶段提交 & 三阶段提交 & paxos:分布式事务与一致性算法Paxos & raft & zab_followMyInclinations的专栏-优快云博客
4. 典型的柔性事务方案
- 最大努力通知(非可靠消息、定期校对)
- 可靠消息最终一致性(异步确保型)
- TCC(两阶段型、补偿型)
5. 场景的分布式事务解决方案
1. 基于XA协议的两阶段提交
XA是一个分布式事务协议,由Tuxedo提出。XA中大致分为两部分:事务管理器(TM)和本地资源管理器(RM)。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。
XA协议比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。但是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,往往并发量很高,XA无法满足高并发场景。
2. 消息事务 + 最终一致性
所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操作成功成功并且对外发消息成功,要么两者都失败,开源的RocketMQ就支持这一特性。并不是所有的mq都支持事务消息,如kafka。此时可以使用独立消息服务、或者本地事务表,由独立的消息服务保证事务性、发送消息至消息队列。
步骤
- A系统向消息中间件发送一条预备消息
- 消息中间件保存预备消息并返回成功
- A执行本地事务
- A发送提交消息给消息中间件
- 如果步骤1错误,整个事务失败,不会执行A的本地操作
- 如果步骤2错误,整个事务失败,不会执行A的本地操作
- 如果步骤3错误,这时候需要回滚预备消息:A系统实现中间件的一个回调接口,由中间件不断执行这个接口,检查A事务是否执行成功,如果失败则回滚预备消息
- 如果步骤4出错,A的本地事务成功,消息中间件通过回调接口,能够检查到A执行成功了,就可以对消息进行提交
问题:如何知道A系统的本地事务是正在执行中还是执行失败(因为都为初始态),这个时间点如何确立,何时询问??虽然可以最终一致性,但是如果B系统一直执行不成功,依然会存在不一致的问题。
3. TCC 编程
所谓的TCC编程模式,也是两阶段提交的一个变种。TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以在线下单为例,Try阶段会去扣库存(还是锁定库存??),Confirm阶段则是去更新订单状态,如果更新订单失败,则进入Cancel阶段,会去恢复库存。
6. 柔性事务:最大努力通知
最大努力通知型适用于一些一致性时间敏感度低的业务,且被动方处理结果不影响主动方的处理结果。
特点
- 不可靠消息:业务活动主动方,在完成业务处理之后,想业务活动的被动方发送消息,直到通知N次后不再通知,允许消息丢失
- 定期校对:业务活动的被动方,根据定时策略,向业务活动方查询(主动提供查询借款),恢复丢失的业务消息
7. TCC两阶段补偿型
TCC:try-confirm-cancel,主要是解决跨服务调用场景下的分布式事务问题。
- try阶段:完成所有业务检查,预留业务资源(准隔离性)
- confirm阶段:确认执行业务操作,不做任何业务检查,只使用try阶段预留的业务资源
- cancel阶段:取消try阶段预留的业务资源
补偿性事务:补偿是一个独立的支持ACID特性的本地事务,用于在逻辑上取消服务提供者上一个ACID事务造成的影响。confirm和cancel就是补偿事务,用于取消try阶段本地事务造成的影响
与两阶段提交的区别:
- 两阶段提交时资源层面上的分布式事务,强一致性,在两阶段提交的整个过程中,一直持有资源的锁(资源实际上一直都是被加锁的),如果有其他人需要操作这个两条记录,name必须等待锁释放
- TCC是业务层面的分布式事务,最终一致性,不会持有资源的锁。
与 DTP 事务模型的区别:
-
TCC 模型中主业务服务相当于DTP模型中的 application,TCC模型中的从业务服务相当于 DTP 模型中的 RM。DTP模型中,应用application操作多个资源管理器RM上的资源,而在TCC模型中,主业务服务操作多个从业务服务上的资源
-
TCC模型中,从业务提供的try-confirm-cancel接口相当于DTP模型中RM提供的 prepare、commit、rollback接口
-
DTC模型和TCC模型中都有一个事务管理器
在DTP模型中,阶段1的(prepare)和阶段2的(commit、rollback),都是由TM进行调用的。
在TCC模型中,阶段1的try接口是主业务服务调用(绿色箭头),阶段2的(confirm、cancel接口)是事务管理器TM调用(红色箭头)。这就是 TCC 分布式事务模型的二阶段异步化功能,从业务服务的第一阶段执行成功,主业务服务就可以提交完成,然后再由事务管理器框架异步的执行各从业务服务的第二阶段。这里牺牲了一定的隔离性和一致性的,但是提高了长事务的可用性
TCC事务模型优缺点:
-
优点:XA两阶段提交资源层面的,而TCC实际上把资源层面二阶段提交上提到了业务层面来实现。有效了的避免了XA两阶段提交占用资源锁时间过长导致的性能低下问题。
-
缺点:主业务服务和从业务服务都需要进行改造,从业务方改造成本更高。