Spring Data Repository 使用更新的审计字段保存不返回实例

Posted

技术标签:

【中文标题】Spring Data Repository 使用更新的审计字段保存不返回实例【英文标题】:Spring Data Repository Save Not Returning Instance With Updated Audit Fields 【发布时间】:2013-12-21 08:46:36 【问题描述】:

为什么 repository.save(myEntity) 不返回具有更新审计字段的更新实体?

来自 MyEntityRepository.save(myEntity) 以及随后来自 MyEntityService.save(myEntity) 的结果实例没有更新的 updatedOn 日期。我已经验证这在数据库中设置正确,所以我知道审计正在工作。返回的实例的 updatedOn 日期对于插入是正确的,但对于更新不正确。我宁愿不必在每次保存后立即执行 findById,特别是如果意图是 save() 返回更新后的附加实例。

假设 updatedOn 的设置是通过 @PreUpdate 钩子发生的,并且这个钩子是在通过 repository.save() 调用 entityManager.merge() 期间触发的,我不明白为什么不会在返回的值上设置该值实例。

示例代码:

@Entity
@DynamicUpdate
@DynamicInsert
@Table(name = "my_entity", schema = "public")
@SequenceGenerator(name = "pk_sequence", sequenceName = "my_entity_seq", allocationSize = 1)
@AttributeOverrides(@AttributeOverride(name = "id", column = @Column(name = "id", columnDefinition = "int")))
@EntityListeners(AuditingEntityListener.class)
public class MyEntity 

    protected Integer id;

    @LastModifiedDate
    private Date updatedOn;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pk_sequence")
    @Column(name = "id", nullable = false, columnDefinition = "bigint")
    public Integer getId() 
        return id;
    

    public void setId(Integer id) 
        this.id = id;
    

    @Version
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "updated_on")
    public Date getUpdatedOn() 
        return updatedOn;
    

    public void setUpdatedOn(Date updatedOn) 
        this.updatedOn = updatedOn;
    



public interface MyEntityRepository extends JpaRepository<MyEntity, Integer>  

@Service
@Transactional(readOnly = true)
public class MyEntityService 

    @Autowired
    private MyEntityRepository repository;

    @Transactional
    public MyEntity save(MyEntity myEntity) 
        return repository.save(myEntity);
    

【问题讨论】:

您是否调试到AuditingEntityListener.touchForUpdate(…) 并查看是否调用了该方法?您确定实体实际上包含更改吗?如果持久性提供程序在实体上找不到任何更改,它甚至可能不会触发事件,即使我们调用EntityManager.merge(…) 是的,我有,它正在被调用。我实际上已经使用 AuditingEntityListener 和我自己的 @PreUpdate 钩子实现了它。两种方法都有效 - 更改以正确的 updatedOn 日期保存到数据库中。但是从 repository.save 或 repository.saveAndFlush 返回的实例没有这些更改的审计字段(但是所有其他更改的数据都正确反映)。 这很奇怪。您是否有机会将其归结为一个小测试用例并针对 Spring Data JPA 提交 JIRA?了解您使用的 JPA 提供程序也很有用。 我会这样做的。提供者是 Hibernate 4.2.6。 【参考方案1】:

我遇到了同样的问题。

就我而言,帮助我解决这个问题的重要项目是: 1)使用repository.saveAndFlush(...)方法

2) 使用findAllById()findByYourOwnQuery()(注解@Query)。

总的来说,我的测试用例如下所示:

UserAccount userAccount = UserAccount.builder().username(username).build();
userAccountRepository.saveAndFlush(userAccount);

final LocalDateTime previousUpdateDate = userAccount.getUpdateDate();
....

List<BigInteger> ids = Arrays.asList(userAccountId);    
UserAccount updatedUserAccount = userAccountRepository.findAllById(ids).get(0);  // contains updated Audit data fields

...
assertThat(actual.getUpdateDate(), is(greaterThan(previousUpdateDate)));  // true

您不应该使用 repository.findOne(...) 的重要一点,因为它缓存了对对象的引用 - read more。

【讨论】:

【参考方案2】:

我遇到了完全相同的问题。我通过使用修复它,

repository.saveAndFlush(myEntity);

而不是

repository.save(myEntity);

【讨论】:

以上是关于Spring Data Repository 使用更新的审计字段保存不返回实例的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data Redis - 对 Repository 的 @Transactional 支持

Spring Data Repository 使用更新的审计字段保存不返回实例

Spring Data JPA Custom Repository

Spring Entity Manager 和 Spring Data Repository 有啥区别?

使用 Spring Data Rest 时如何从组件扫描中排除 @Repository

如何在 Spring Data Repository Method 中使用 Regex 关键字