这种模式下,我们需要操作的目标字段,都要添加一个相关的冻结字段,try操作是操作冻结字段,cc操作时,将冻结的数值更新到目标字段。 示例如下:
<!--try逻辑-->
<update id="increaseMoney">
UPDATE company SET frozen = frozen + #{money}
WHERE id = #{id}
</update>
<!--confirm逻辑-->
<update id="confirmIncreaseMoney">
UPDATE company SET money = money + #{money},frozen = frozen - #{money}
WHERE id = #{id}
</update>
<!--cancel逻辑-->
<update id="cancelIncreaseMoney">
UPDATE company SET frozen = frozen - #{money}
WHERE id = #{id}
</update>
这种模式,是使用一个反向的业务操作,来撤销之前的业务操作。SAGA模式,try阶段直接操作目标字段,不需要使用冻结字段,和TCC模式相比,saga不需要confirm操作。
设想一种场景:A->B,C,D。这种场景下,如果发生如下情况:
显然,不管是TCC还是SAGA模式,try出问题了,都会进入cancel阶段,但是,恰巧,在BC刚try成功D失败了,但是还未来得及回滚的情况下,有用户来读取BCD的值。
那么,这种情况下,使用TCC和SAGA,结果是不一样的。
在TCC中,由于try操作的是冻结字段,所以,其他用户在try和cancel的间隙来读数据,那么读的数据也是正确的,因为目标字段并没有发生改变。
在SAGA中,由于直接操作的目标字段,所以,try阶段,由于数据已经提交了,那么其他用户在try和cancel的间隙来读取数据,读到的数据,就是有问题的“脏数据”。
当然,看起来只有在2PC模型下,才不存在这个“脏读风险”。
关于这个问题,推荐几篇文章看看: mysql的四种隔离级别 fescar锁设计和隔离级别的理解