1. 概述
在这篇文章中,我们将讨论如何在Hibernate中使实体、集合或属性变为不可变(Immutable)。默认情况下,字段是可变的,这意味着我们可以执行改变它们状态的操作。
2. Maven
为了启动项目,我们需要在pom.xml中添加必要的依赖。由于我们使用Hibernate,我们需要添加相应的依赖:
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.2.Final</version>
</dependency>
同时,因为我们将使用HSQLDB,还需要添加:
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.7.1</version>
</dependency>
3. 实体上的注解
首先,定义一个简单的实体类:
@Entity
@Immutable
@Table(name = "events_generated")
public class EventGeneratedId {
@Id
@Column(name = "event_generated_id")
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
// standard setters and getters
}
你可能已经注意到,我们在实体上添加了Immutable注解。如果我们尝试保存一个Event:
@Test
public void addEvent() {
Event event = new Event();
event.setId(2L);
event.setTitle("Public Event");
session.save(event);
session.getTransaction().commit();
session.close();
}
输出应该是这样的:
Hibernate: insert into events (title, event_id) values (?, ?)
即使我们移除注解,输出也不会改变,这意味着无论是否添加实体注解,都不会影响操作结果。
另外,我们在EventGeneratedId实体中添加了GeneratedValue注解,但这仅在创建实体时起作用。这是因为它指定了ID生成策略,由于Immutable注解的存在,其他操作不会影响Id字段。
3.1. 更新实体
现在,保存实体没有问题,让我们尝试更新它:
@Test
public void updateEvent() {
Event event = (Event) session.createQuery(
"FROM Event WHERE title='New Event'").list().get(0);
event.setTitle("Private Event");
session.update(event);
session.getTransaction().commit();
}
Hibernate会简单地忽略update
操作,而不会抛出异常。然而,如果移除Immutable注解,我们会得到不同的结果:
Hibernate: select ... from events where title='New Event'
Hibernate: update events set title=? where event_id=?
这告诉我们,对象现在是可变的(如果未包含注解,默认值),并且允许更新操作进行。
3.2. 删除实体
对于删除实体:
@Test
public void deleteEvent() {
Event event = (Event) session.createQuery(
"FROM Event WHERE title='New Event'").list().get(0);
session.delete(event);
session.getTransaction().commit();
session.close();
}
无论实体是否可变,我们都可以执行删除操作:
Hibernate: select ... from events where title='New Event'
Hibernate: delete from events where event_id=?
4. 注解在集合上
到目前为止,我们已经了解了注解对实体的影响,但正如开头所说,它也可以应用于集合。
首先,向Event类添加一个集合:
@Immutable
public Set<String> getGuestList() {
return guestList;
}
同样,我们提前添加了注解。如果我们尝试向集合中添加元素:
org.hibernate.HibernateException:
changed an immutable collection instance: [com.baeldung.entities.Event.guestList#1]
这次我们收到异常,因为不允许添加或删除集合。
4.1. 删除集合
当集合不可变且设置了*@Cascade*注解时,另一个会抛出异常的情况是试图删除它。
所以,当Immutable存在且尝试删除时:
@Test
public void deleteCascade() {
Event event = (Event) session.createQuery(
"FROM Event WHERE title='New Event'").list().get(0);
String guest = event.getGuestList().iterator().next();
event.getGuestList().remove(guest);
exception.except(PersistenceException.class);
session.saveOrUpdate(event);
session.getTransaction().commit();
}
输出:
org.hibernate.HibernateException:
changed an immutable collection instance:
[com.baeldung.entities.Event.guestList#1]
5. XML 注解说明
最后,配置也可以通过XML的mutable=false属性来完成:
<hibernate-mapping>
<class name="com.baeldung.entities.Event" mutable="false">
<id name="id" column="event_id">
<generator class="increment"/>
</id>
<property name="title"/>
</class>
</hibernate-mapping>
但由于我们主要使用注解方法实现示例,这里不会详细讲解XML配置。
6. 总结
在这篇简短的文章中,我们探讨了Hibernate中的有用Immutable注解,以及它如何帮助我们在数据上定义更好的语义和约束。
如往常一样,所有这些示例和片段的实现可以在GitHub项目中找到。这是一个基于Maven的项目,导入和运行起来应该很容易。