这里需要一些帮助,我不能理解为什么我的事务在异常事件中不回滚。
我会尽量把我的代码尽可能接近,因为它是在项目上(不能在互联网上共享)
这是我的服务
@Service
@SL4j
@Transactional(propagation = propagation.SUPPORTS, readOnly=true)
public class PublicationServiceImpl implements PublicationService{
@Autowired
private PartnerRepo partnerRepo;
@Autowired
private FlowRepo flowRepo;
@Autowired
private PubRepo pubRepo;
@Override
@Transactional(propagation = propagation.REQUIRED, rollbackFor=Exception.class)
public int save(Request request) {
try{
int pk_id_partner = partnerRepo.save(request);
int pk_id_flow = flowRepo.save(request);
String publicationCode = generatePubCode(request);
int publicationCode= pubRepo.save(pk_id_partner, pk_id_flow, request);
}
catch(Exception e){
log.error("Exception in saving");
}
return 0;
}
}
这是我的存储库(示例1,所有3个存储库都遵循相同的编码标准)
@Repository
@Slf4j
public class PartnerRepo implemets PartnerRepo{
@Autowired
private NamedParamaterJDBCTemplate namedParamaterJDBCTemplate;
//String Declarations .....
private MapSqlParameterSource sqlParameterSource;
@Override
public int save(Request request){
sqlParamatersSource = new MapSqlParameterSource();
//sqlParamatersSource.addValue(.....)
//sqlParamatersSource.addValue(.....)
//sqlParamatersSource.addValue(.....)
return executeQuery();
}
private int executeQuery(){
try{
keyHolder = new GenerateKeyHolder();
namedParamaterJDBCTemplate.update(getInsertQuery(), sqlParamaterSource , kekHolder, new String[]{"pk_id"})
return keyHolder.getKey().intValue();
}catch(Exception e){
log.error("Exception while saving");
return 0;
}
}
}
所以问题是,考虑到generatePubCode(request);
方法中有一个异常,理想情况下,因为我已经在类级别和方法级别使用了@Transactional
,前面的2个repo事务()应该回滚吗?然而,它没有发生,即使在代码完成执行后,我也可以看到DB中的记录(Postgres DB v10)。
请帮助解决这个问题,我做了什么根本错误?
请让我知道,如果你需要进一步的信息,可能会有所帮助!
P. S:我已经尝试了@Transactional
的所有排列,没有工作:只有在catch块中有这个才有效! TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
我想知道这是否是springBoot项目的正确方法
提前感谢您的帮助!
编辑:根据PublicationServiceSaverImpl.save()
公开的建议
最好的药剂师,巴伽夫。
7条答案
按热度按时间mnemlml81#
在Spring中,有几种情况会破坏正常的事务
1.您的服务方式为
private
1.您正在捕获并接受异常
private
方法你的
PublicationServiceImpl
save
方法是private
的事实基本上使得@Transactional
在那个方法上是无用的。因为private
方法不能被代理,所以没有事务将被应用。即使它是public
,它也不会工作,因为你从同一个对象中调用该方法,因此该方法的事务性被应用。要修复,请使您的方法
public
并从其他类调用save
方法(或使调用save
的实际方法具有正确的@Transactional
)。事实上,这是不工作的是由于类型的操作AOP正在使用,默认情况下,Spring将使用代理,这是一个缺点,使用代理为基础的AOP。
另一个让它与
private
方法一起工作的解决方案是切换到成熟的AspectJ,在编译时或加载时编织类,这两种方法都需要额外的设置,可能会很乏味。捕获并吞下异常
在存储库和服务中都有一个
try/catch
块,每个块都捕获并吞下异常(它们被记录但不会被重新抛出)。要使事务正常工作,它需要看到异常。您捕获并吞下它们的事实使事务方面看不到它们,因此不执行回滚,而是执行提交。对于事务方面,一切正常,因为没有异常。
要修复,请删除
try/catch
或重新引发异常。11dmarpk2#
由于Spring中代理的创建方式,注解通常不会对从同一个类调用的方法起作用。
它与@Transaction没有特别的关系,而是与您的方法是private和从同一对象内调用这一事实有关。
请将方法设置为public,并将@Transactional方法移动到标有@Service的单独类中,然后从类示例外部调用它
必须从类PublicationServiceSaverImpl的外部调用保存方法,可能是从PublicationServiceImpl调用。
qlvxas9a3#
如果要使用
@Transactional
,则方法PublicationServiceImpl.save
必须为public
。根据Spring文件:
在Spring的标准配置下使用事务代理时,您应该只对具有公共可见性的方法应用@Transactional注解。如果您确实使用@Transactional注解了受保护的、私有的或包可见的方法,则不会引发任何错误,但注解的方法不会显示配置的事务设置。
sulc1iza4#
首先:公开你的方法。
第二:你必须抛出异常。如果你捕获了它而没有重新抛出,你怎么能期望事务处理知道发生了错误,然后回滚呢?
您有两种选择:抛出
Exception
而不是捕获它,或者捕获,做一些进一步的处理,然后重新抛出它。因此,在存储库中,只需添加一个throws关键字,然后在log语句之后重新抛出异常:
现在,为了你的服务:
示例1-使用throws关键字传播已检查异常:
示例2-捕获并将其作为RuntimeException重新抛出,该异常未被选中。
注意,第二个示例不需要
@Transactional
的rollbackFor
参数,默认情况下,如果发生未检查的异常,事务将回滚,因此在RuntimeException
的情况下不需要显式使用rollbackFor
。jmp7cifd5#
如果解决方案不起作用,则必须进行另一个验证。它是验证数据库表是否允许回滚。为此,引擎必须位于InnoDB中,而不是MyISAM和其他位置。
lnvxswe26#
在我的例子中,在Application类上添加@EnableTransactionManagement注解解决了这个问题
blpfk2vs7#
提供@事务性(传播=传播.REQUIRED_NEW,而不是@事务性(传播=传播.REQUIRED
如果使用后者,它将使用父事务边界,该边界位于类级别。
而且您不需要显式地声明rollbackFor= Exception.class。
并将私有更改为公共
试试这个