当前位置: 首页 > 知识库问答 >
问题:

JPAHibernate不会更新实体对象,即使从数据库加载它

龙嘉誉
2023-03-14

我有我的问题的简单例子。有两个学生和三个科目。起初,学生1拥有所有科目,学生2没有科目。关系是一个学生和多个学科的关系。

我正在尝试使用jpa hibernate将subject1从学生1交换到学生2。在数据库中出现事务提交更改后:主题表的外键student_id发生了更改,但在java中,即使我从数据库加载学生1,对象仍然具有subject1。

@Entity
@Table(name = "STUDENTS")
public class Students {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ST_ID")
    private int id;


    @OneToMany(mappedBy = "student", cascade = CascadeType.ALL)
    List<Subject> subjects = new ArrayList<>();
    //getters and setters....
}



@Entity
@Table(name = "SUBJECT")
public class Subject {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "SB_ID")
    private int id;

    @Column(name = "MARK")
    private int mark;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "ST_ID")
    private Students student;
    //getters and setter....
}

主要代码:

    public static void main(String[] args) throws Exception {
    
        EntityManager em = Persistence.createEntityManagerFactory("Test").createEntityManager();
//        em.getTransaction().begin(); //does not work
        Students student1 = getStudentById(1, em); //load student1 from database by id
        Students student2 = getStudentById(2, em); //load student2 from database by id
        
        Subject subject1 = getSubjectById(1, em); //load subject1 from database by id
        Subject subject2 = getSubjectById(2, em); //load subject2 from database by id
        Subject subject3 = getSubjectById(3, em); //load subject3 from database by id
        System.out.println("student1 subjects");
        for(Subject sb : student1.getSubjects()){
            System.out.println(sb.getId()); //prints subjects: 1,2,3
        }
        System.out.println("\nstudent2 subjects");
        for(Subject sb : student2.getSubjects()){
            System.out.println(sb.getId()); //prints no subjects
        }    
        //swap subject1 between student1 and student2
        subject1.setStudent(student2);
        student2.getSubjects().add(subject1);
        
        //save changes
        em.getTransaction().begin();
        em.persist(student2);
        em.persist(student1);
        em.persist(subject2);
        em.persist(subject1);
        //em.merge does't work
        //em.flush(); //doesn't work
        em.getTransaction().commit();
        
        student1 = getStudentById(1, em); //load student1 from database by id
        System.out.println("\nstudent1 subjects");
        for(Subject sb : student1.getSubjects()){
            System.out.println(sb.getId()); //and still student1 has subject1
        }
    
        student2 = getStudentById(2, em); //load student2 from databse by id
        System.out.println("\nstudent2 subjects");
        for(Subject sb : student2.getSubjects()){
            System.out.println(sb.getId()); //now student2 also has subject1
        }
    
        
    }
    
    public static Students getStudentById(int id, EntityManager em){
        Query query = em.createQuery("from entity.Students where ST_ID="+id);
        return (Students)query.getSingleResult();
    }
    public static Subject getSubjectById(int id, EntityManager em){
        Query query = em.createQuery("from entity.Subject where SB_ID="+id);
        return (Subject) query.getSingleResult();
    }

提交后主题表如下所示。它显示id为1的科目现在有id为2的学生。

只有在提交后进行em.refresh时,实体对象student1才会更新,但我不明白为什么从数据库加载student1时需要使用refresh?而且我也不确定,刷新实体是一种好的做法吗?

共有1个答案

李景天
2023-03-14

您必须了解,如果可能的话,Hibernate会从一级缓存或持久性上下文返回对象,以保留对象标识。因此,即使使用查询从数据库中加载学生,它也只会返回之前持久化的对象,因为它与持久化上下文关联。

当您想从数据库中重新加载状态时,您必须使用刷新分离,然后执行查询。

 类似资料:
  • 我目前正在重构遗留代码,以使用Android架构组件,并在一种存储库模式中设置一个房间数据库和截取请求。因此,表示层/域层要求存储库获取LiveData对象进行观察,或告诉他与服务器同步,然后删除旧的db条目,并从服务器中重新提取所有当前条目。 我已经写了同步部分的测试,所以我确信,对象被正确地获取并插入到数据库中。但是当写一个测试来观察db表的条目时(并测试对象是否被正确保存,以及在将它们放入d

  • 我想知道ehcache是否有办法检测数据库更新/插入(spring/java,hibernate web应用程序),并使用数据库中的当前(最新)数据刷新其缓存。如果没有,检测数据库更新的最佳方法是什么,以保持与缓存和数据库之间的数据同步?

  • 问题内容: 我将一些对象存储在切片中。在将其附加到切片之前,我先打印对象的名称。 将其存储在切片中之后,我将其检索为指针,并希望将名称更改为,但是更改仍然有效,因为它仍然可以打印。为什么? 问题答案: 每当方法想要修改接收者时, 它都必须是指向该值的指针 ;该方法必须具有指针接收器。 如果方法具有非指针接收者,则在调用该方法时将创建并传递一个副本。从那时起,无论您对接收器做什么,都只能修改副本,而

  • 问题内容: 我有必须转换为JSON的Hibernate实体,并且必须转换实体中的某些值,但是当我转换值时,这些值会立即保存到数据库中,但是我不想将这些更改保存到数据库中。有没有解决此问题的方法? 问题答案: 您可以通过调用分离实体。 其他选择是在转换值之前为您的实体创建防御性副本,或者在该代码中使用DTO代替该实体。我认为这些选项更优雅,因为它们不将转换转换为JSON和持久层。

  • 问题内容: 在启动时如何从数据库表中加载规则并从Drools 6.2.0中的同一表中更新规则呢?我找到了一个使用Drools 5 的示例,我可能可以将它从Scala转换为Java,但看起来API发生了巨大变化……例如,我看不到RuleBaseFactory类。 任何样品或文件将不胜感激。 问题答案: 我不确定从哪儿拿来的。以下是在Drools 5.3(可能更早)至5.6中的完成方式: 省略号指示用

  • 我在我的GAE数据存储实验中发现了一些很奇怪的东西。我使用的是GAE SDK 1.7.5。我不确定我的发现是否正确。 基本上,我发现在执行数据存储get之前,将实体放入数据存储并进行计数不会返回正确的值。 如果你想更深入地挖掘,这里是我前面的SO问题中的实际代码: