我正在使用JPA注释进行基本的hibernate,我有一个问题。我创建了一个带有结构的虚拟项目 -
一个实体类人
@Id
@GeneratedValue(strategy=GenerationType.TABLE, generator="personIdGenerator")
private int personIdentifier;
private String firstName;
private String lastName;
private String title;
private String sex;
@ElementCollection(fetch=FetchType.LAZY)
@MapKeyEnumerated(EnumType.STRING)
@javax.persistence.MapKeyColumn(name="ADDRESS_TYPE")
private Map<AddressType,Address> address = new HashMap<AddressType, Address>();
一个可嵌入的类地址 -
private String streetAddressLane1;
private String streetAddressLane2;
private String streetAddressLane3;
@ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY)
private City city;
最后是一个实体类城市 -
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int cityId;
private String city;
private String state;
private String country;
private String zipCode;
现在我有一个主要方法,代码为 -
SessionFactory sesFac = new Configuration().configure().buildSessionFactory();
Session session = sesFac.openSession();
Transaction tx = session.beginTransaction();
// session.save(city);
//session.save(adr);
Person person = (Person) session.get(Person.class, 101);
//Employee empNew = (Employee)session.merge(emp);
//empNew.setEmpId(2);
// System.out.println(person.getAddress().get(AddressType.HOME_ADDRESS).getCity().getZipCode());
//Employee empOld= (Employee) session.get(Employee.class, empNew.getEmpId());
session.getTransaction().commit();
session.flush();
session.close();
session = sesFac.openSession();
tx = session.beginTransaction();
// session.save(city);
//session.save(adr);
person.setLastName("gggggg");
session.saveOrUpdate(person);
//Employee empNew = (Employee)session.merge(emp);
//empNew.setEmpId(2);
//Employee empOld= (Employee) session.get(Employee.class, empNew.getEmpId());
session.getTransaction().commit();
session.close();
在主要方法中,我得到两个不同的会话和两个不同的事务。在第一个我得到人员ID 101的记录,这已经存在于数据库中,在第二个事务中,我将姓氏设置为gggggg。
现在因为我正在使用延迟初始化,所以当我尝试更改名称并将其传递给saveOrUpdate方法时,不应该有任何地址和城市。因此,这应该删除分配给人员ID 101的现有地址,但事实并非如此。地址仍在那里,姓氏正在改为ggggg。我无法理解这可能是什么原因。 hibernate创建的代理是否处理这种更新或什么?
答案 0 :(得分:1)
&#34;未加载&#34;与&#34;删除&#34;不同,Hibernate跟踪它加载的所有内容的差异。
在这种特定情况下,当Hibernate加载Person
实体时,它会将address
字段包装在PersistentMap
中,该字段最初被标记为尚未加载。如果您要访问address
字段并读取或更改其中的任何内容,PersistentMap
将在当时从数据库加载其内容,并跟踪某些内容已更改。然后,Hibernate会在提交时保存更改。
当你没有读取或更改address
字段时,当Hibernate处理提交时,它会检查PersistentMap
,发现它从未被加载,并继续忽略它,使数据部分保持不变
如果要清除address
数据,则需要明确这样做。 Hibernate试图避免数据的意外更改,并且处理从未加载与删除相同的内容将非常容易发生事故。
答案 1 :(得分:0)
如果关闭会话,则会分离Person实体。当你调用saveOrUpdate()
时,hibernate会将分离的对象重新附加到新的Session中。
为了执行延迟加载,Hibernate将Person包装在扩展Person的代理类中。初始化检查在此代理中完成。这意味着如果您从未在第一个会话中访问数据库中的地址,则代理将知道这一点,并且当实体在第二个会话中重新附加时,它会将地址视为未初始化而不是从数据库中删除它们。