网站 稳定性,学生诚信档案建设网站,重庆网站建设小能手,辽宁省住房和城乡建设厅网站换了文章目录 XA模式实现XA模式 AT模式AT模式的脏写问题#xff08;对同数据并发写的问题#xff09;其他事务不获取全局锁的一个情况#xff08;AT模式写隔离的实现#xff09;实现AT模式 TCC模式TCC实现我们怎么样去判断是否空回滚和业务悬挂#xff1f;业务分析 Saga模式总… 文章目录 XA模式实现XA模式 AT模式AT模式的脏写问题对同数据并发写的问题其他事务不获取全局锁的一个情况AT模式写隔离的实现实现AT模式 TCC模式TCC实现我们怎么样去判断是否空回滚和业务悬挂业务分析 Saga模式总结 XA模式
XA模式分为两种情况 提交成功
提交失败 具有强一致性seata相当于是在RM上做了一层封装 XA模式 优点 1.事务的强一致性只要有失败的TC事务协调者就会发送信息让RM回滚——满足ACID原则 2.没有代码侵入常用数据库都支持 缺点 1.第一阶段就要锁定数据库资源但是却不提交从而导致数据库所占用的资源不能释放占数据库锁性能较差 2.依赖关系型数据库实现事务 实现XA模式
步骤
1.在yaml文件中开启XA代理模式
2.添加GlobalTransactional注解开启全局事务 AT模式 利用快照来保证事务的一致性来进行数据回滚 AT模式是一种最终一致的模式因为RM资源管理器执行sql后会直接提交那么此时如果是数据不一致的情况下那么说明肯定是软一致但是在阶段二时AT模式RM资源管理器会利用快照进行数据回滚从而保证最终一致 AT模式直接提交有利于提高效率 AT模式的脏写问题对同数据并发写的问题
脏写问题造成数据空转现象
什么是脏写 简而言之就是两个事务并发执行修改同一条数据我第一个事务修改并且提交之后释放DB锁资源第二个事务想要进行回滚那么就会导致脏写——前一个事务修改无效 解决对事务2造成数据空转现象进行处理 1.事务1先获取DB锁并且保存快照 ——2.然后执行业务sql我们在提交事务前获取全局锁防止一提交事务释放DB锁后其他事务立马插入获取DB锁更改sql ——3.此时全局锁会记录操作当前数据的事务让该事务持有全局锁然后提交事务释放DB锁 ——4.此时其他事务可以争夺DB锁执行业务sql ——5.然后和之前一样它也要获取全局锁但是全局锁此时已经被事务1拿了所以它会进行自旋300ms ——6.然后事务1如果此时要根据快照恢复数据那么就需要DB锁但是DB锁此时被其他事务拿了 ——7.死锁现象发生 ——8.还好其他事务重试失败后会释放锁资源因为获取全局锁失败那么后面的事务提交也进行不了 ——9.事务1再次拿到DB锁可以进行快照恢复数据了 其他事务不获取全局锁的一个情况AT模式写隔离的实现
利用了CAS的思想
实际上是有两份快照的before-image、after-image
跟cas一样before是我们要回滚目标的状态而after是相当于验证的一个状态如果满足after的内容就可以设置为before
如果不一样不满足的话就会判断不能恢复回滚那么我们可以记录异常发送警告 总结 AT在第一阶段RM直接提交事务释放数据库资源不需要像XA模式那样还需要将状态返回给TC事务协调者还利用了全局锁实现读写分离将表执行的事务储存起来相当于一个标识 并且**没有代码侵入seata自动完成回滚和提交——seata相当于RM资源管理器的一个代理** 实现AT模式
数据库表中lock_table:全局锁undo_log放的是快照信息 可以再下单途中在业务代码中加上断点的方式查看数据库表中记录的快照信息和AT模式的全局锁信息 他们会在业务结束时自动销毁清理干净
TCC模式 那我们TCC模式是怎么保证一致性
首先我们想想AT模式在第一阶段通过对数据库锁的获取完成事务事务都是隔离的所以有人成功有人失败只有在二阶段完成回滚才能够保证数据的最终一致性中间还是出现了软状态
而TCC模式为什么就不需要锁了呢我们AT模式是利用全局锁来保证一致性的——执行sql后提交前上一道全局锁那么其他事务的sql就执行不了进行自旋超时就释放DB锁而TCC解决利用了每个事务都是预留资源进行处理—— 第一个事务冻结的金额和第二个事务冻结的金额是不一样的跟其他事务是没有关系的那么回滚事务也是跟其他事务不影响的不需要加锁类似Semaphore
简而言之就是把事务所用到的资源预留起来 等后面的结果再来判断是扣除还是释放预留起来后数据库原表中的数据已经扣除了所以其他的业务请求也不会有影响 TCC模式的关键在于有代码侵入需要考虑Comfirm成功提交和Cancel数据回滚的编写 优点1.TCC第一阶段直接提交事务提交完直接释放数据库资源AT的话也是直接执行但是使用了全局锁来保存事务操作的一个状态保证其他事务争夺不了XA的话第一阶段就垃圾了不会提交sql业务需要把状态给到TC事务协调者进行判断是否回滚还是提交是一提交或者回滚就是全局那种 2.无需生成快照与全局锁依赖的是一个补偿操作因为事务直接提交的原则所以其他事务是操作不到自己的可用于非关系型数据库 TCC实现
具体模式还得根据场景来比如TCC就很像Semaphore一般来说是对一个共享资源进行操作比如停车场的停车位库存…像下单服务就不适合了因为你每次调用都是一个新的订单
一个事务是可以有多个模式实现的 我们怎么样去判断是否空回滚和业务悬挂
利用两者相互判断 根据冻结金额的那张表来判断 在进行try业务前 先查询一下冻结金额的表中的数据是否为空 如果不为空则证明已经执行了CANCEL操作 则需要直接拒绝try的操作反之在进行cancel业务前需要根据事务id查询一下冻结金额的表中的数据是否为空 如果为空的话则证明try业务还没做需要进行空回滚同时也需要记录数据new一个新的对象将冻结金额设为0以及其他数据set进去
业务分析 我们可以在BusinessActionContext中获取里面的参数
事务表表示事务冻结金额冻结金额状态发生改变——表示那部分被锁定
事务id用户id冻结金额和状态 业务方便代码的实现:
Slf4j
Service
public class AccountTCCServiceImpl implements AccountTCCService {Autowiredprivate AccountMapper accountMapper;Autowiredprivate AccountFreezeMapper accountFreezeMapper;OverrideTransactionalpublic void deduct(String userId, int money) {//0.获取事务idString xid RootContext.getXID();// 判断是否有冻结记录 有的话直接拒绝执行try业务AccountFreeze Freeze accountFreezeMapper.selectById(xid);if (Freeze!null) {//拒绝return;}//1.扣减可用余额accountMapper.deduct(userId, money);//2.记录冻结金额记录事务状态AccountFreeze accountFreeze new AccountFreeze();accountFreeze.setUserId(userId);accountFreeze.setFreezeMoney(money);accountFreeze.setState(AccountFreeze.State.TRY);accountFreeze.setXid(xid);accountFreezeMapper.insert(accountFreeze);}Overridepublic boolean confirm(BusinessActionContext ctx) {//0.获取事务idString xid ctx.getXid();//1.删除数据int count accountFreezeMapper.deleteById(xid);return count 1;}Overridepublic boolean cancel(BusinessActionContext ctx) {//0.查询冻结记录AccountFreeze accountFreeze accountFreezeMapper.selectById(ctx.getXid());String userId (String) ctx.getActionContext(userId);//0.2.判断是否空回滚if (accountFreeze null){accountFreeze new AccountFreeze();accountFreeze.setUserId(userId);accountFreeze.setFreezeMoney(0);accountFreeze.setState(AccountFreeze.State.CANCEL);accountFreeze.setXid(ctx.getXid());accountFreezeMapper.insert(accountFreeze);return true;}//0.3 幂等判断if (accountFreeze.getState()AccountFreeze.State.CANCEL){//已经处理过cancel了 无需重复业务return true;}//1.恢复可用余额accountMapper.refund(accountFreeze.getUserId(),accountFreeze.getFreezeMoney());//2.将冻结金额清零 改状态为cancelaccountFreeze.setFreezeMoney(0);accountFreeze.setState(AccountFreeze.State.CANCEL);int count accountFreezeMapper.updateById(accountFreeze);return count 1;}
}Saga模式
与TCC模式类似但是TCC第一阶段只是将资源进行冻结真正的去除还是在第二阶段的而Saga模式是直接提交本地事务第二阶段直接操作事务本身成功则什么都不做失败则通过编写补偿业务来进行回滚
与AT相比没有用锁与TCC比没有冻结资源性能较好
失败用自定义的补偿来写
缺点
没有保证隔离性既没有隔离预留资源又没有上锁容易出现脏写 总结