Hibernate中@Immutable注解
1. 概述
在本文中,我们将讨论如何在 Hibernate中使实体、集合或属性不可变 。
默认情况下,字段是可变的,这意味着我们能够对它们执行更改其状态的操作。
2. Maven
为了让我们的项目启动并运行,我们首先需要将必要的依赖项添加到我们的pom.xml中。当我们使用 Hibernate 时,我们将添加相应的依赖 项:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.7.Final</version>
</dependency>
而且,因为我们正在使用HSQLDB ,所以我们还需要:
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.4</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='My Event'").list().get(0);
event.setTitle("Public Event");
session.saveOrUpdate(event);
session.getTransaction().commit();
}
Hibernate 将简单地忽略update操作而不抛出异常。但是,如果我们删除*@Immutable*注解,我们会得到不同的结果:
Hibernate: select ... from events where title='My Event'
Hibernate: update events set title=? where event_id=?
这告诉我们的是我们的对象现在是可变的(如果我们不包含注解,mutable是默认值)并且将允许更新完成它的工作。
3.2. 删除实体
删除实体时:
@Test
public void deleteEvent() {
Event event = (Event) session.createQuery(
"FROM Event WHERE title='My Event'").list().get(0);
session.delete(event);
session.getTransaction().commit();
}
无论它是否可变,我们都可以执行删除:
Hibernate: select ... from events where title='My 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.blogdemo.entities.Event.guestList#1]
这次我们遇到了一个异常,因为对于集合,我们不允许添加或删除它们。
4.1. 删除集合
另一种情况是Collection是不可变的,它会在我们尝试删除并且我们设置了*@Cascade*注解时抛出异常。
因此,只要存在*@Immutable*并且我们尝试删除:
@Test
public void deleteCascade() {
Event event = (Event) session.createQuery(
"FROM Event WHERE title='Public Event'").list().get(0);
String guest = event.getGuestList().iterator().next();
event.getGuestList().remove(guest);
session.saveOrUpdate(event);
session.getTransaction().commit();
}
输出:
org.hibernate.HibernateException:
changed an immutable collection instance:
[com.blogdemo.entities.Event.guestList#1]
5. XML 注解
最后,也可以通过mutable=false属性使用 XML 进行配置:
<hibernate-mapping>
<class name="com.blogdemo.entities.Event" mutable="false">
<id name="id" column="event_id">
<generator class="increment"/>
</id>
<property name="title"/>
</class>
</hibernate-mapping>
但是,由于我们基本上使用注解方法实现了示例,因此我们不会使用 XML 进行详细介绍。