Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate 在@PostPersist中修改的字段在数据库中不更新_Hibernate_Jpa - Fatal编程技术网

Hibernate 在@PostPersist中修改的字段在数据库中不更新

Hibernate 在@PostPersist中修改的字段在数据库中不更新,hibernate,jpa,Hibernate,Jpa,MyEntity是一个具有生成id的经典JPA实体。我希望自动将字段(myStringField)设置为基于id的值。在本例中,如果id为43,我希望将其设置为“foo43” 由于id是由DB自动生成的,因此在em.persist(myEntity)调用之前它是空的。但是在persist之后,它有一个由Hibernate分配的id(在DB序列上称为NEXTVAL)。因此,我考虑声明@PostPersist方法,如下所示: package ...; import javax.persistenc

MyEntity是一个具有生成id的经典JPA实体。我希望自动将字段(myStringField)设置为基于id的值。在本例中,如果id为43,我希望将其设置为“foo43”

由于id是由DB自动生成的,因此在em.persist(myEntity)调用之前它是空的。但是在persist之后,它有一个由Hibernate分配的id(在DB序列上称为NEXTVAL)。因此,我考虑声明@PostPersist方法,如下所示:

package ...;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PostPersist;


@Entity
public class MyEntity {

    @Id   @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String myStringField;

    @PostPersist
    public void postPersist(){
        System.out.println("The id = " + id);
        this.myStringField = "foo" + id;
    }

    public String getMyStringField() {
        return myStringField;
    }
    ...
}
以下是一些创建和保存实体的代码:

package ...;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@Service
public class MySpringBean {
   @PersistenceContext EntityManager em;

   public void createMyEntity() {
       MyEntity myEntity = new MyEntity();
       em.persist(myEntity);
       System.out.println(myEntity.getMyStringField());
   }
}
它打印以下输出:

The id = 47
foo47
这很好。但是,在数据库中,myStringField字段为空!有人知道为什么吗

我确实希望在MyEntity.postPersist()方法中实体会被标记为dirty,并且在刷新过程中事务结束时会发生更新。但显然不是

我使用HibernateV4.2.4


有人知道为什么这个数据库记录有空值吗?

您是在持久化后执行的,所以它发生在写入数据库之后

根据对规格说明的回答


这些数据库操作可能在调用持久化、合并或删除操作后直接发生,也可能在刷新操作发生后直接发生。

保存MyEntity后@PostPersist代码正在运行。因此,如果要确保使用更新的值“foo”+id保存字段myStringField,那么在@PostPersist代码之后,需要再次保存实体

因此,如果您将代码更改为:

   MyEntity myEntity = new MyEntity();
   em.persist(myEntity);
   em.persist(myEntity);

理论上,这应该正确地保存更新后的myStringField。不过这有点尴尬。不确定你的整个用例,但是你可以考虑在数据库本身写一个“插入触发器”,它会帮你处理这个问题。我做了额外的测试,事实上,在刷新期间调用了@PostPersist(可能是因为在刷新期间发送了SQL插入)。总之,事情的发生顺序是:1。em.persist(),1.1 NEXTVAL发送到DB并分配myEntity.id,到达@Transactional方法的2个结尾并执行刷新。2.1向DB发送插入信息。2.2@PostPersist已调用。2.2.1 myEntity.myStringField已分配,实体已脏。然后不再执行进一步的刷新(以及脏检查和更新)=>无数据库保存。非常感谢

使用

@PrePersist
相反,但是您的方法字段生成对我来说是不正确的,因为如果您的myStringField即将成为一个业务id,不同于jpa id,那么您应该假设它是在bean初始化时创建的


有关如何处理业务id的更多示例,我建议您查看关于equals()/hashcode()困境的线程,特别是下面的回答:

要回答您的问题,您不应该在数据层中做这种事情。插入和更新应该由业务逻辑层处理

但是如果在数据层中确实需要@PrePersist,请使用它