You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在事务方法中刷新实体以获取数据库触发器修改的属性值?

如何在事务方法内刷新实体,使触发器修改的属性可见?

我有一个在插入/更新前设置或更新特定列的触发器,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 04:42:04