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

Rom*_*man 128 java orm serialization hibernate jpa

问题出在标题中.下面我刚才描述了我的一些想法和发现.

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

但是当域模型变得更复杂时,我得到了RuntimeException,它说我的一个实体没有实现Serializable.

我使用Hibernate作为JPA实现.

我想知道:

  1. 是特定于供应商的要求/行为吗?
  2. 我的可序列化实体会发生什么?它们是否可以序列化以便存储或传输?
  3. 在哪一刻,有必要使我的实体可序列化?

Con*_*nor 104

根据JPA规范:

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

"JSR 220:Enterprise JavaBeansTM,Version 3.0 Java Persistence API Version 3.0,Final Release May 2,2006"

  • 我不明白为什么会有这么多的赞成.OP表示,当模型更简单时,不需要它.通过Java序列化远程发送对象总是要求对象可以序列化,无论其复杂程度如何.显然这不是OP的用例. (18认同)
  • (+1)看规范总是富有成效 (13认同)
  • 这个答案只是一个信息转储,根本不能帮助别人理解原因。 (3认同)
  • 我不太确定 hibernate,但对于其他 JPA 提供程序,有些操作要求提供程序复制实体(对象)。“可序列化”可能对此有所帮助,并且在持久性方面比“可克隆”更一致。 (2认同)

Aar*_*lla 54

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


Boz*_*zho 51

Serializable如果需要通过线程传输它们(将它们序列化为其他表示形式),则需要您的实体,将它们存储在http会话中(通过servlet容器将其序列化为硬盘)等.

仅仅为了持久性,Serializable不需要,至少使用Hibernate.但制作它们是最好的做法Serializable.

  • @dancarter - 这完全是无稽之谈,也是对 Josh Bloch 关于该主题的建议的错误描述。序列化是语言和运行时的重要组成部分。它当然不是为支持“遗留”代码而保留的。在许多情况下,您应该或必须实现 Serialized。但是,如果没有充分的理由且不了解后果,您不应该这样做。Josh 的观点是,在不知道为什么或如何安全地实现 Serialized 的情况下,该语言使得实现 Serialized 变得太容易了。 (3认同)
  • 我不知道,也许我的实体在某个地方被隐含地转移了.我使用hibernate + spring + jsf和Tomcat.这个链转移可以在哪里进行? (2认同)
  • Java 的最佳实践是**不**使类可序列化,除非出于遗留原因绝对必须这样做。请参阅 Josh Block 所著的《Effective Java》。什么使其成为 JPA 的最佳实践?好吧,这是一个老答案,现在通过网络传输对象或存储在 http 会话中的需要应该很少见了。 (2认同)
  • 关于现在非常旧的原始帖子和同样旧的答案:JPA 提供程序在内存和辅助存储中广泛使用缓存。对于除最简单的实现之外的所有实现,这都需要实体的序列化。二级缓存通常是持久的,以便恢复和/或溢出到磁盘。JPA 提供者有时还必须制作实体的“复写”副本,并且要求实现可序列化接口是支持此操作的最可靠方法。 (2认同)

Vla*_*cea 26

JPA规范

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

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

休眠

Hibernate 只要求实体属性是Serializable,而不是实体本身。

然而,实现 JPA 规范,所有关于Serializable实体的 JPA 要求也适用于 Hibernate。

雄猫

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

每当 Apache Tomcat 正常关闭并重新启动时,或者触发应用程序重新加载时,标准管理器实现将尝试将所有当前活动的会话序列化到通过路径名属性定位的磁盘文件。当应用程序重新加载完成时,所有这些保存的会话将被反序列化和激活(假设它们同时没有过期)。

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

因此,如果实体存储在 中HttpSession,则它应该实现Serializable.


Ank*_*hal 19

如果我们只谈持久化,Serializable是不需要的,但是最好的做法是制作实体Serializable

如果我们将domain/entities对象直接暴露给表示层,而不是使用DTO,那么我们需要实现Serializable. 可以存储这些域对象以HTTPSession用于缓存/优化目的。http-session 可以被序列化或集群。并且在JVM-instances之间传输数据也需要它。

当我们使用DTO解耦持久层和服务层时,将域对象标记为Serializable会适得其反,并且会违反“ encapsulation”。然后它变成了一种反模式。

复合标识符

主键类必须是可序列化的。

POJO 模型

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

缓存
此外,如果您要实现clustered第二级,cache那么您的实体必须是serializable. 标识符必须是Serializable因为这是 JPA 要求,因为它identifier可能用作二级缓存条目的键。

当我们序列化实体时,请确保提供显式serialVersionUID的私有访问修饰符。因为如果一个serializable类没有显式声明serialVersionUID,那么序列化运行时将根据serialVersionUID该类的各个方面计算该类的默认值,如 Java(TM) 对象序列化规范 中所述。默认serialVersionUID计算对可能因编译器实现而异的类细节高度敏感,因此可能会InvalidClassExceptions在反序列化期间导致意外。

  • 缓存+1。这个答案很详细。只是落地晚了所以分数不高。 (2认同)

Sym*_*Sym 8

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

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

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


小智 7

根据hibernate文档,在使用@JoinColumn注释时:

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

  • 谢谢你的解释。我将“@JoinColumn”与“refenrecedColumnName”一起使用到另一个表中的非主唯一列。这导致了“ClassCastException”,因为 hibernate 无法序列化实体类。 (4认同)

Avn*_*evy 6

我相信你的问题与一个没有注释的复杂类型(类)的字段有关.在这种情况下,默认处理将在数据库中以序列化形式存储对象(这可能不是你想要做的)示例:

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

@Entity
Class Customer {
  CustomerData getCustomerData();
  void setCustomerData(CustomerData data)
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,CustomerData将以序列化形式保存在数据库的字节数组字段中.


小智 6

请参阅http://www.adam-bien.com/roller/abien/entry/do_jpa_entities_have_to 它说,java.io.Serializable 的实现只是在 JVM 实例之间通过 IIOP 或 JRMP (RMI) 传输数据所必需的。在纯 Web 应用程序的情况下,域对象有时存储在 HTTPSession 中以用于缓存/优化目的。http 会话可以序列化(钝化)或集群。在这两种情况下,所有内容都必须是可序列化的。


jar*_*bjo 5

如果要序列化类,则必须实现 Serializable。这与 JPA 没有直接关系,并且 JPA 规范不要求实体是可序列化的。如果 Hibernate 真的抱怨这个,我想这是一个 Hibernate 错误,但我想你直接或间接地对实体做了一些其他的事情,这需要它们是可序列化的。