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

时间:2010-01-07 14:17:09

标签: java hibernate serialization orm jpa

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

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

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

我使用Hibernate作为JPA实现。

我想知道:

  1. 是供应商特定的要求/行为吗?
  2. 我的可序列化实体会怎样?它们是否可以序列化以便存储或转移?
  3. 在哪一刻有必要让我的实体可序列化?

14 个答案:

答案 0 :(得分:104)

根据JPA规范:

  

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

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

答案 1 :(得分:50)

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

答案 2 :(得分:45)

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

仅仅为了持久性,不需要Serializable,至少在Hibernate中是这样。 但最佳做法是Serializable

答案 3 :(得分:15)

JPA规范

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

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

休眠

休眠只要求实体属性为Serializable,而不是实体本身。

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

Tomcat

根据Tomcat documentationHttpSession属性也必须为Serializable

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

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

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

答案 4 :(得分:8)

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

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

与CDI的JEE6战争项目:Beans that use session, application, or conversation scope must be serializable, but beans that use request scope do not have to be serializable.因此,基础JPA实体bean -if any将遵循相同的语义。

答案 5 :(得分:6)

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

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

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

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

答案 6 :(得分:6)

根据hibernate docs,使用@JoinColumn注释:

  

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

答案 7 :(得分:4)

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

答案 8 :(得分:3)

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

答案 9 :(得分:1)

远程命中使用postman或ajax或angular js等.....,可能会导致重复循环与StackOverflow异常与Jackson fastxml.So,最好使用序列化器。

答案 10 :(得分:1)

如果我们仅讨论持久性,则不需要Serializable,但是最好的方法是使实体Serializable

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

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

Composite identifiers

主键类必须可序列化。

POJO Models

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

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

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

答案 11 :(得分:0)

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

答案 12 :(得分:0)

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

使用diskstore作为二级缓存实现ehcache(即在实体或存储库/服务方法上使用@Cacheable注释)需要Serializable,否则缓存将失败(NotSerializableException)将实体写入磁盘高速缓存中。

答案 13 :(得分:0)

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