【问题标题】:Data not saved in db when the time @PostPersist got called调用@PostPersist 时数据未保存在数据库中
【发布时间】:2020-06-06 16:24:08
【问题描述】:

在数据库中创建对象后,我需要向其他微服务发送请求。我只发送对象 ID,因此其他微服务需要再次调用 db 以获取包含其他内容的信息。

但是,当其他微服务尝试使用接收到的 id 查找记录时,它无法在数据库中找到保存的记录。

即使@postPersist 被调用,我尝试调试似乎也不会保留记录。 它会在@PostPersist 被执行后保存。

有没有人可以为此提供解决方法。我真的需要再次查询数据库,因为这是自定义要求。我使用mysql和spring boot

public class EmployeeListener {

    @PostPersist
    public void sendData(Employee employee){
        Long id = employee.getEmployeeId();
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.exchange("http://localhost:8081/service/employee"+id, HttpMethod.POST, null, String.class);

    }

}


@Entity
@EntityListeners(EmployeeListener.class)
public class Employee {
       //
}

【问题讨论】:

  • 什么是 JPA 版本?
  • 我使用的是 spring boot 1.5.4 版本。它使用休眠 5.0.12

标签: java database spring spring-data-jpa entitylisteners


【解决方案1】:

问题在于 JPA 生命周期事件发生在与您的保存操作相同的事务中,但查找,因为它发生在不同的服务器上,必须仅在您的事务关闭后发生。

因此,我推荐以下设置:在Collection 中收集需要通知的 id,然后在事务完成时发送数据。

如果您想在一种方法中进行发送操作和保存操作,[TransactionTemplate][1] 可能比通过注释进行事务管理更好用。

您也可以考虑Domain Events。请注意,它们仅在实际调用 save 时触发。这些事件的好处是它们使用ApplicationEventPublisher 发布,其中侦听器是 Spring Bean,因此您可以注入任何您认为有帮助的 bean。他们仍然需要一种方法来打破如上所述的交易

【讨论】:

    【解决方案2】:

    @PostPersist 注解的方法在同一个事务中被调用,并且默认的 flash 模式是 AUTO,这就是你在数据库中看不到记录的原因。您需要强制刷新:

    @Component
    public class EmployeeListener {
    
        @PersistenceContext
        private EntityManager entityManager;
    
        @PostPersist
        public void sendData(Employee employee){
            // Send it to database
            entityManager.flush();
            Long id = employee.getEmployeeId();
            RestTemplate restTemplate = new RestTemplate();
            restTemplate.exchange("http://localhost:8081/service/employee"+id, HttpMethod.POST, null, String.class);
    
        }
    
    }
    

    注意EmployeeListener 需要是 Spring 托管的 bean。

    【讨论】:

    • 感谢您的建议,我会试一试。但是这些侦听器不受弹簧上下文管理。因此我不确定制作@component 是否可行
    • @user3318021 组件注解正是因为这个原因:让它成为spring管理的。
    • 我试过但没用。entityManager 总是 null 。放置@component 并不能使其正常工作。因为spring不管理jpa监听器
    • 我设法让 EnitiyManager 使用 ApplicationContextAware 但是当 flush() 被调用时,它会抛出异常 org.hibernate.AssertionFailure: null id in entry(发生异常后不要刷新 Session)
    • @user3318021 你能在 Github 上做一个概念验证项目吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2015-03-13
    • 2016-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多