JPA实体何时以及为何应实现Serializable接口?


151

问题在标题中。下面我仅描述了我的一些想法和发现。

当我有一个非常简单的域模型(3个表没有任何关系)时,我所有的实体都没有实现Serializable。

但是,当域模型变得更加复杂时,我遇到了RuntimeException,它表示我的一个实体没有实现Serializable。

我使用Hibernate作为JPA实现。

我想知道:

  1. 它是特定于供应商的要求/行为吗?
  2. 我的可序列化实体会怎样?它们应该可序列化以存储或传输吗?
  3. 在什么时候有必要使我的实体可序列化?

Answers:


59

如果混合使用HQL和本机SQL查询,通常会发生这种情况。在HQL中,Hibernate将您传入的类型映射到数据库可以理解的任何类型。运行本机SQL时,必须自己进行映射。如果您不这样做,则默认的映射是序列化参数并将其发送到数据库(以希望它能理解它)。


这并不能解释为什么只是“也许如何”看到下面的答案,来自Bozho
chrips 19-10-21

这意味着实体将在不实现可序列化接口的情况下保存在数据库中?
Hanumantha_3048092

@ Hanumantha_3048092是的。实体映射和Serializable是两个不同的概念。
亚伦·迪古拉

@AaronDigulla您可以通过示例或伪代码来解释它。
sdindiver

110

根据JPA规范:

如果要通过值将实体实例作为分离的对象(例如,通过远程接口)传递,则实体类必须实现Serializable接口。

“ JSR 220:Enterprise JavaBeansTM,版本3.0 Java Persistence API版本3.0,最终版本,2006年5月2日”


14
(+1)查看规格总是富有成果
Bozho 2010年

20
我看不出为什么会有这么多的反对意见。OP表示,模型更简单时不需要。通过Java序列化远程发送对象将始终要求对象是可序列化的,无论其复杂性如何。显然,这不是OP的用例。
罗宾(Robin)

我不太确定休眠状态,但是对于其他JPA提供程序,有一些操作要求提供程序制作实体(对象)的副本。Serializable这可能会有所帮助,并且在持久性方面比例如保持一致Cloneable
JimmyB

这个答案只是一个信息转储,根本无法帮助别人理解原因。
chrips

59

Serializable如果需要通过有线方式传输它们(将它们序列化为其他表示形式),将它们存储在http会话中(然后由servlet容器序列化到硬盘上)等,则需要实体。

仅仅为了持久性,Serializable就不需要了,至少对于Hibernate而言。但是制作它们是一种最佳实践Serializable


2
我不知道,也许我的实体正在隐式转移到某个地方。我使用hibernate + spring + jsf和Tomcat。在这个链条中的何处可以转移?
罗马

例如,@ Roman当前用户(可能是一个实体)及其所有相关实体可能会在会话中结束,正如Bozho所说,可以通过Servlet容器将其序列化到磁盘。
OrangeDog

这是“为什么和何时”的最佳答案!明确!谢谢
chrips 19-10-21

13

根据休眠文档,在使用@JoinColumn批注时:

它还有一个名为的参数referencedColumnName。此参数声明目标实体中将用于联接的列。请注意,使用referencedColumnName非主键列时,关联的类必须为Serializable


8

为了补充Conor提到JSR-317规范的好答案。通常,EAR项目由EJB模块组成,并且EJB通过远程接口公开。在这种情况下,您需要使实体Bean可序列化,因为它们在远程EJB中进行了聚合,并且可以通过网络进行连接。

没有CDI的JEE6 war项目:可以包含由不可序列化JPA实体支持的EJB lite。

使用CDI的JEE6战争项目:使用会话,应用程序或会话范围的Bean必须可序列化,但是使用请求范围的Bean不必可序列化。因此,底层的JPA实体bean(如果有)将遵循相同的语义。


7

如果我们只讨论持久性,Serializable则不是必需的,但是使实体成为最佳实践Serializable

如果我们将domain/ entities对象直接暴露给表示层,而不是使用DTO,那么在这种情况下,我们需要实现Serializable可以将这些域对象存储在其中HTTPSession以进行缓存/优化。http会话可以序列化或集群化。而且,在JVM-instances 之间传输数据也是必需的。

当我们DTO用来分离持久层和服务层时,将域对象标记为Serializable适得其反并且会违反“ encapsulation”。然后,它成为反模式。

复合标识符

主键类必须可序列化。

POJO模型

如果实体实例要作为分离对象远程使用,则实体类必须实现该Serializable接口。

缓存
另外,如果要实施clustered第二级,cache则您的实体必须为serializable。该标识符必须是Serializable因为这是JPA要求,因为identifier可能将用作第二级缓存条目的键。

并且当我们序列化实体时,请确保提供显式serialVersionUID的私有访问修饰符。因为如果一个serializable类没有显式声明a serialVersionUID,那么序列化运行时将根据serialVersionUID该类的各个方面为该类计算一个默认值,如Java™Object Serialization Specification中所述。默认serialVersionUID计算对类详细信息高度敏感,类详细信息可能会根据编译器的实现而有所不同,因此可能导致InvalidClassExceptions反序列化期间发生意外情况。


6

我相信您的问题与具有未注释的复杂类型(类)的字段有关。在这种情况下,默认处理将把对象以其序列化形式存储在数据库中(这可能不是您想要的目的)。

Class CustomerData {
    int getAge();
    void setAge(int age);
}

@Entity
Class Customer {
  CustomerData getCustomerData();
  void setCustomerData(CustomerData data)
}

在上述情况下,CustomerData将以其序列化形式保存在数据库的字节数组字段中。


5

JPA规范

根据JPA规范,Serializable仅当实体需要从一个JVM传递到另一个JVM或该实体由有状态会话Bean使用且需要被EJB容器钝化时,才应实现该实体。

如果要通过值将实体实例作为独立对象(例如,通过远程接口)传递,则实体类必须实现该Serializable接口。

冬眠

Hibernate仅要求实体属性为Serializable,而不要求实体本身。

但是,实施JPA规范后,有关Serializable实体的所有JPA要求也适用于Hibernate。

雄猫

根据Tomcat的文档HttpSession属性还需要为Serializable

只要Apache Tomcat正常关闭并重新启动,或者触发了应用程序重载,标准Manager实施就会尝试将所有当前活动的会话序列化为通过pathname属性定位的磁盘文件。然后,当应用程序重新加载完成时,所有此类保存的会话将被反序列化并激活(假设它们同时没有过期)。

为了成功恢复会话属性的状态,所有这些属性必须实现java.io.Serializable接口。

因此,如果实体存储在中HttpSession,则应实施Serializable


4

如果要序列化类,它们必须实现Serializable。这与JPA不直接相关,并且JPA规范不要求实体可序列化。如果Hibernate确实对此有所抱怨,那么我想它是一个Hibernate错误,但是我想您直接或间接地对实体做其他事情,这要求它们可序列化。



1

使用postman或ajax或angular js等....远程命中可能会导致Jackson更快的StackOverflow异常重复循环,因此,最好使用序列化程序。


1
  1. 在什么时候有必要使我的实体可序列化?

将ehstore与磁盘存储区实现为第二级缓存(即,使用@Cacheable实体或存储库/服务方法上的注释)需要可序列化,否则缓存将无法(NotSerializableException)将实体写入磁盘缓存。


0

当您将错误输入的ID作为第二个参数传递给诸如em.find()之类的第二个参数(即传递实体本身而不是其ID)时,也会引发此错误。我还没有发现实际上需要声明可序列化的JPA实体-除非您使用的是aman所描述的referencedColumnName,否则实际上并没有必要。


0

当远程EJB操作将JPA实体用作参数或返回值时

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.