Spring:@Transactional一次排查问题记录

博客围绕微服务架构中B服务插入表数据时出现的ORA - 02291错误展开。分析了可能的原因,如外键关联表无数据、外键环、数据类型和长度不一致等。排查发现与事务隔离级别有关,因涉及分布式事务,原设置无效。最后给出去掉A中方法事务、去掉外键约束等解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.服务异常描述
微服务架构,根据日志定位到错误是在B服务的某个方法插入表数据时抛出的,错误代码是:

ORA-02291: 违反完整约束条件 (*) - 未找到父项关键字

伪代码如下:

@Transactional
public void serviceB(){
  int update = xxxMapper.save(beanB);
}

数据库用的是Oracle,错误提示也很明显.
ORA-02291: 违反完整约束条件 (*) - 未找到父项关键字总体说说可能出现的原因:情况场景:表A中有个字段是外键,关联了表B中的某字段,再往表A插入数据时,会出现这种情况。可能原因:1.在往A表插入时,外键关联的字段在B表中必须有数据,如果B表中没有数据则又这种情况。 2.产生了外键环,就是B表中被外键关联的字段又关联了C表中的字段,而C中相应字段却没有数据,则产生这种情况。3.如果不是上两种情况,那么就是一个非常容易疏忽的问题:A中的外键字段和B中的被外键关联字段数据类型和长度不一致。特别是数据长度,必须要一致。第三种情况是最容易忽略的,希望大家注意。
然后通过PL/SQL查看benaB对应的表假设为table_b中的外键约束,发现错误提示的外键约束表假设为table_a,table_b中的外键假设为FK_tableA_tableB,约束关系为table_b(id_tableA)->table_a(id),而id_tableA对应的字段值是另一个服务A远程调用传过来的,假设A中的伪代码如下:

@Transactional(readOnly = false, rollbackFor = { Exception.class })
public void submitData(){
  int update = xxxMapper.save(beanA);
  HttpClient.post(B.serviceB(paramJson));
  ...
}

在A服务中,先进行beanA数据保存(beanA对应的表为table_a),保存成功id会自动会写到beanA中,然后在 HttpClient.post(B.serviceB(paramJson))会传递到过去.

二.问题排查
table_a和table_b位于同一个数据库下,schema相同,且在服务A和服务B中连接串相同.
A服务中明明保存成功了,值也传到位了,为什么还说找不到呢?
看到了@Transactional注解,想到了可能和隔离级别有关.
假设隔离级别为READ_COMMITTED,A服务中的保存成功了,但此时事务还未提交,然后到了B服务中在保存时会因为强外键约束,读取不到A中还未提交的数据报了错误.既然这样,我代码中设置下A服务submitData()方法的隔离级别:

@Transactional(readOnly = false, rollbackFor = { Exception.class },isolation = Isolation.READ_UNCOMMITTED)
public void submitData(){
  int update = xxxMapper.save(beanA);
  HttpClient.post(B.serviceB(paramJson));
  ...
}

我把隔离级别改成读未提交的,结果测试报出如下错误:这里写图片描述
百度了下,原来oracle只支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别,且默认系统事务隔离级别是READ COMMITTED,也就是读已提交.其实想想也知道,这中即使支持也是不起作用的,毕竟是跨jvm了,涉及到分布式事务了.

三.解决办法
1.去掉A中方法的事务,同时为了防止A服务保存数据成功了,但B服务调用失败,产生脏数据,进行代码编程手动删除替代自动回滚操作.
2.去掉外键约束
另注:在这中场景下,传播机制是不起作用的.
考虑是否要上个分布式事务呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值