写入调用/事务被丢弃在 TransactionalEventListener

Posted

技术标签:

【中文标题】写入调用/事务被丢弃在 TransactionalEventListener【英文标题】:Write call/transaction is dropped in TransactionalEventListener 【发布时间】:2017-09-29 05:57:32 【问题描述】:

我正在使用 spring-boot(1.4.1) 和 hibernate(5.0.1.Final)。我注意到,当我尝试从 @TransactionalEventListener 处理程序中写入数据库时​​,调用被简单地忽略了。读取调用工作得很好。 当我说忽略时,我的意思是数据库中没有写入,也没有日志。我什至启用了 log4jdbc,但仍然没有日志,这意味着没有创建休眠会话。据此,我认为,在 spring-boot 的某个地方,我们确定它是一个事务事件处理程序并忽略了一个 write 调用。

这是一个例子。

// This function is defined in a class marked with @Service
@TransactionalEventListener
open fun handleEnqueue(event: EnqueueEvent) 
    // some code to obtain encodeJobId
    this.uploadService.saveUploadEntity(uploadEntity, encodeJobId)


@Service
@Transactional
class UploadService 
    //.....code

    open fun saveUploadEntity(uploadEntity: UploadEntity, encodeJobId: String): UploadEntity 
        // some code
        return this.save(uploadEntity)
    

现在,如果我通过注释来强制执行新事务

@Transactional(propagation = Propagation.REQUIRES_NEW)
saveUploadEntity 

建立了一个新的连接事务,一切正常。

    我不喜欢在删除此写入时日志中完全静默(再次读取成功)。是否存在已知错误?

    如何启用处理程序来启动新事务?如果我对我的 handleEnqueue 事件执行 Propogation.Requires_new,它就不起作用。

此外,启用 log4jdbc 成功记录读/写我在春天有以下设置。

谢谢

【问题讨论】:

【参考方案1】:

我遇到了同样的问题。这种行为实际上是在 TransactionSynchronization#afterCompletion(int) 的文档中提到的,它由 TransactionPhase.AFTER_COMMIT(这是 @TransactionalEventListener 的默认 TransactionPhase 属性)引用:

事务将已提交或回滚,但事务资源可能仍处于活动状态且可访问。因此,此时触发的任何数据访问代码仍将“参与”原始事务,允许执行一些清理(不再有提交!),除非它明确声明它需要在单独的事务中运行。因此:对从这里调用的任何事务操作使用 PROPAGATION_REQUIRES_NEW。

不幸的是,这似乎除了通过 Propagation.REQUIRES_NEW 强制执行新事务之外别无选择。问题是 transactionalEventListener 被实现为事务同步,因此绑定到事务。当事务关闭并且其资源被清理时,侦听器也是如此。可能有一种方法可以使用自定义的 EntityManager 存储事件,然后在调用其 close() 后发布它们。

请注意,您可以在 @TransactionalEventListener 上使用 TransactionPhase.BEFORE_COMMIT,这将在事务提交之前发生。这会将您的更改写入数据库,但您不知道您正在侦听的事务是实际提交还是即将回滚。

【讨论】:

以上是关于写入调用/事务被丢弃在 TransactionalEventListener的主要内容,如果未能解决你的问题,请参考以下文章

Spring中同一个service中方法相互调用事务不生效问题解决方案

从另一个方法调用的@Transactional 方法没有获得事务

spring @Transactional 传播机制(参数 propagation )

@Transactional 注意事项方法调用

Spring——事务注解@Transactional建议收藏

SpringBoot设置 @Transactional ,并在异常处理中调用setRollbackOnly()事务不回滚