Hibernate 的级联更新
引言
上一篇文章中,我提到 Hibernate 的查询可以不用 SQL,而本篇,我要分享的是 Hibernate 的实体更新。因为 Hibernate 的这一特性,同样让我在开发的过程中,感受到了省心和劳心。
Hibernate 内实体的四种状态
什么是实体?其实就是对象。而 Hibernate 内的实体分为四种状态:临时态、持久态、游离态、删除态
,
临时态(transient)
:刚用 new 语句创建,还没有被持久化,并且不处于 Sesssion 的缓存中。处于临时状态的 Java 对象被称为临时对象。
持久态(persistent)
:已经被持久化,并且加入到 Session 的缓存中。处于持久化状态的 Java 对象被称为持久化对象。
游离态(detached)
:已经被持久化,但不再处于 Session 的缓存中。处于游离状态的 Java 对象被称为游离对象。
删除态(removed)
:不再处于 Session 的缓存中,并且 Session 已经计划将其从数据库中删除。处于删除状态的 Java 对象被称为删除对象。
各状态之间的切换,我仅给出一张图进行简单说明,建议想深入了解的朋友查阅有关文章。
持久态下,针对该实体任何属性的更改都会直接影响到数据库表中一条记录对应字段的更新,即与数据库表同步。
同步的时机也建议查询下相关文章,不在赘述。
这是很方便的一个特性。举个例子 Book:
public class Book implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;
@Column(nullable = false, insertable = false, updatable = false)
Integer peopleId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "peopleId")
People people;
private String name;
}
在一个服务中,如果需要进行修改书的名称,几行代码搞定:
public void update(Integer Id) {
Book book = bookRepository.findById(Id);
book.setName("New Name");
}
是的,当实体处于持久态下,如果需要更新实体的一些属性,直接 set 就好了,十分方便。
问题及解决
但是,只要是对象,就无可避免的会与其他对象进行关联。我引入一个新对象 People 来说明由此引发的一些问题:
public class People implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;
private String name;
}
在一个服务中,如果需要修改与 Book 关联的 People,使用同样的 set 方法是不行的,会报错:
public void updatePeople(Integer Id) {
Book book = bookRepository.findById(Id);
book.setPeopleId(100);
}
注意这行注解:
@Column(nullable = false, insertable = false, updatable = false)
Integer peopleId;
在 Hibernate 中,如果对象需要关联,那么,关联的键值必须添加Column(nullable = false, insertable = false, updatable = false)
注解,但是一旦添加上此注解,set 是不允许的,那么,如果要进行关联对象更新,如何做到呢,正确的方式如下:
public void updatePeople(Integer Id) {
Book book = bookRepository.findById(Id);
book.setPeople(new People(100));
}
是的,直接更新关联对象,而不是更新关联键值,这才是正确的 Hibernate 进行关联对象更新的方式。