【问题标题】:How to perform an operation before a transaction is started of before it is committed?如何在事务开始之前或提交之前执行操作?
【发布时间】:2020-03-13 18:42:21
【问题描述】:

我必须在事务提交之前在一个特殊的global temporary table 中执行插入操作。

这是由于旧的数据库设计使用此表在每个业务表上使用触发器执行审计操作。另一个用 C 编写的软件使用这种模式来执行对代码影响很小的审计:

  • 建立连接时在临时表中插入审计数据
  • 执行各种插入/更新,触发器会将这些操作与审计数据关联起来
  • 提交:审核日期从临时表中刷新

现在我有一个 Spring Boot + JPA (Hibernate) 应用程序,它开始使用相同的数据库,我需要重现这种模式。 然而,对于事务的 Spring + JPA 抽象,我很难找到一种方法来复制这种行为。

我需要在创建事务时(或在提交事务之前)插入审计数据。 我已经检查了这个有希望的TransactionalEventListener,但看起来我必须声明一个发布者并在每个服务中手动触发事件,就像在following example 中一样:

@Service
public class CustomerService {
    private final CustomerRepository customerRepository;
    private final ApplicationEventPublisher applicationEventPublisher;
    public CustomerService(CustomerRepository customerRepository, ApplicationEventPublisher applicationEventPublisher) {
        this.customerRepository = customerRepository;
        this.applicationEventPublisher = applicationEventPublisher;
    }
    @Transactional
    public Customer createCustomer(String name, String email) {
        final Customer newCustomer = customerRepository.save(new Customer(name, email));
        final CustomerCreatedEvent event = new CustomerCreatedEvent(newCustomer);
        applicationEventPublisher.publishEvent(event);
        return newCustomer;
    }
}

正如您在此示例中看到的,服务声明了一个ApplicationEventPublisher,并且需要在每次更新/插入后调用applicationEventPublisher.publishEvent(event);

这并不能满足我的需求:我真的需要能够在每次 commit() 之前执行此操作,并且对于所有服务和存储库来说这必须是自动的。

我已经开始研究基于 AOP 的解决方案,但我觉得它有点矫枉过正。

那么有什么简单的解决方案可以在 Spring Boot + JAP 上下文中的任何提交之前执行一些操作吗?

【问题讨论】:

  • 你试过@EventListener(Customer.class) @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
  • 假设您正在使用 HIbernate,请编写一个休眠事件侦听器或拦截器并在其中执行此操作。不要与 Spring 事件侦听器和拦截器或 AOP 混淆。或者作为最后的手段,您始终可以为 PlatformTransactionManager 创建一个包装器,并在委派给实际的事务管理器之前在其中执行此操作。
  • @Ganesh 问题是我想要一个完全自动化的系统,而不是在我的所有服务上添加事件发布者。您是否想到了以这种自动化方式使用 TransactionalEventListener 的示例?
  • @Deinum,感谢您的提示,Hibernate 拦截器看起来是个不错的选择,我会尝试弄清楚如何为我的项目设置一个!

标签: java spring spring-boot jpa spring-transactions


【解决方案1】:

JPA 为您提供了事件监听工具。

您可以使用 @EntityListener(YourListener.class) 注释标记您的实体:

@Entity
@EntityListeners(YourListener.class)
...
public class Entity implements Persistable<>

YourListener 应该是这样的:

public class YourListener<T extends Persistable> {
    @PostUpdate
    public void onPostPersist(T entity) {
        //do
    }
}

several annotations标记监听器的方法,你可以选择以下钩子:@(PrePersits/PreUpdate/PreRemove/PostPersits/PostUpdate/PostRemove/PostLoad)。

确保在执行侦听器期间不要使用相同的 EntityManager 来节省任何额外费用!请参阅https://stackoverflow.com/a/42222592/5661496 和其他答案。

我个人最终会启动新的 Hibernate 会话,以防我需要将数据保存在另一个实体中。

【讨论】:

  • 这种方法的问题是每次刷新实体时都会调用一次我的自定义预持久操作。这可能是一个有趣的解决方法,但不是最有效的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-15
  • 1970-01-01
  • 2011-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
相关资源
最近更新 更多