如何在事务方法中刷新实体以获取数据库触发器修改的属性值?
如何在事务方法内刷新实体,使触发器修改的属性可见?
我有一个在插入/更新前设置或更新特定列的触发器,PostgreSQL示例如下:
CREATE TRIGGER customer_befins BEFORE INSERT ON customer FOR EACH ROW EXECUTE PROCEDURE tr_update_managementfields();
后端我有一个事务方法用于创建并返回实体,补充实体映射代码如下:
@MappedSuperclass public abstract class BaseEntity implements Serializable { private static final long serialVersionUID = 1L; @Id @GenericGenerator(name = "IdGenerator", strategy = "demo.IdGenerator") @GeneratedValue(generator = "IdGenerator") @Column(columnDefinition = "bpchar", updatable = false) private String id; @Column(name = "somedate", columnDefinition = "TIMESTAMP") private LocalDateTime someDate; public BaseEntity() { } public String getId() { return this.id; } public void setId(String id) { this.id = id; } public LocalDateTime getSomeDate() { return this.someDate; } public void setSomeDate(LocalDateTime someDate) { this.someDate = someDate; } } @Entity public class CustomerEntity extends BaseEntity { private static final long serialVersionUID = 1L; @Column(name = "name", nullable = false) private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } public interface ICustomerRepository extends JpaRepository<CustomerEntity, String>, JpaSpecificationExecutor<CustomerEntity> { } @Service public class CustomerService { private final EntityManager entityManager; private final ICustomerRepository repository; public CustomerService(EntityManager entityManager, ICustomerRepository repository) { this.entityManager = entityManager; this.repository = repository; } @Transactional public CustomerEntity createEntity(...) { CustomerEntity entity = new CustomerEntity(); // ... 设置实体属性 entity = repository.save(entity); // 此处需要获取触发器修改后的值 return entity; } }
执行save后,触发器修改的属性在实体中不可见,本例中触发器修改了someDate对应的列。
我首先尝试在调用repository.save()后直接用entityManager.refresh(entity)刷新实体,但出现如下错误:
jakarta.persistence.EntityNotFoundException: No row with the given identifier exists: [this instance does not yet exist as a row in the database
我已查阅过相关问题,但未找到可行解决方案。
解决办法
1. 用saveAndFlush强制刷库后再刷新
save()方法在事务内可能不会立即将数据写入数据库,导致refresh时找不到对应行。改用saveAndFlush()强制把数据刷入数据库,再执行refresh:
@Transactional public CustomerEntity createEntity(...) { CustomerEntity entity = new CustomerEntity(); // ... 设置属性 entity = repository.saveAndFlush(entity); entityManager.refresh(entity); return entity; }
2. 直接重新查询实体
如果refresh还是有问题,直接通过ID从数据库重新查询,能确保拿到触发器修改后的最新数据:
@Transactional public CustomerEntity createEntity(...) { CustomerEntity entity = new CustomerEntity(); // ... 设置属性 entity = repository.save(entity); // 重新查询获取最新数据 return repository.findById(entity.getId()).orElseThrow(() -> new RuntimeException("实体不存在")); }
3. 检查自定义ID生成器的时机
你的ID用了自定义生成器demo.IdGenerator,要确认它在实体创建时就已经生成了有效的ID,而不是延迟到数据库插入阶段。如果ID生成太晚,save后数据库里还没对应的行,自然会触发找不到的错误。
4. 给触发器修改的字段加@Generated注解(Hibernate专属)
对于触发器修改的字段,添加Hibernate的@Generated注解,让框架自动在插入/更新后读取最新值,无需手动刷新:
在BaseEntity的someDate字段上修改:
@Column(name = "somedate", columnDefinition = "TIMESTAMP") @Generated(value = GenerationTime.ALWAYS) private LocalDateTime someDate;
这个注解会告诉Hibernate,每次执行insert或update后,都要从数据库同步该字段的值。
内容的提问来源于stack exchange,提问作者QStorm
相关产品推荐
相关产品推荐

