seata的事务@GlobalTransactional对PG数据库的insert on conflict回滚无效
·
问题描述
@GlobalTransactional
public void inStock(Input input) {
...
rpc.xxx;
repository.generateSku(skuIds);
if (Objects.equals(CommodityType.ASSIT,input.getCommodityType())) {
throw new XXXException("xxx");
}
rpc.xxx;
...
}
@Transactional
public void generateSku(Set<Integer> skuIds) {
...
mapper.insertIgnore(xxxPO);
...
}
<insert id="insertIgnore">
INSERT INTO commodity_sku ( sku_id,...)
VALUES ( #{sku_id} )
ON CONFLICT (sku_id) DO NOTHING;
</insert>
当执行了带有insert on conflict语句后,如果发生冲突,数据库中原来就有某条数据,是不会执行insert操作;且后续执行过程中,程序抛出了业务异常;那么seata就会误认为这条原来就在的数据是insert进去的,并在回滚中将其删除,导致原有的数据消失。
排查过程
在generateSku的方法下一段代码(if判断处)打断点(seata会在一个事务执行完后才会插入undo_log),此时查看undo_log的rollback_info(Text)信息;可以看到seata将这条sql标记为普通的INSERT类型;

同时,在io.seata.sqlparser.SQLType中,我们也找不到一个类型能够对应上pg的insert on conflict;(INSERT_ON_DUPLICATE_UPDATE是针对mysql的);查阅官网,也可以得知,seata并不支持对postgres数据库的insert on conflict回滚。
解决方案
把insert on conflict改成先查一遍,对比数据后,按需正常insert插入没有的数据即可;
更多推荐
所有评论(0)