Когда и почему сущности JPA должны реализовывать интерфейс Serializable?

Вопрос в заголовке. Ниже я только что описал некоторые свои мысли и выводы.

Когда у меня была очень простая модель предметной области (3 таблицы без каких-либо отношений), все мои объекты НЕ реализовали Serializable.

Но когда модель предметной области стала более сложной, я получил RuntimeException, в котором говорилось, что одна из моих сущностей не реализовала Serializable.

Я использую Hibernate в качестве реализации JPA.

Я думаю:

  1. Это специфичное для поставщика требование / поведение?
  2. Что происходит с моими сериализуемыми объектами? Должны ли они быть сериализуемыми для хранения или передачи?
  3. В какой момент становится необходимым сделать сериализованную мою сущность?

11 ответов

Решение

Обычно это происходит, если вы смешиваете HQL и нативные SQL-запросы. В HQL Hibernate сопоставляет передаваемые вами типы с тем, что понимает БД. Когда вы запускаете собственный SQL, тогда вы должны сделать отображение самостоятельно. Если вы этого не сделаете, то по умолчанию сопоставление заключается в сериализации параметра и отправке его в базу данных (в надежде, что он это понимает).

Согласно спецификации JPA:

Если экземпляр сущности должен передаваться по значению как отдельный объект (например, через удаленный интерфейс), класс сущности должен реализовывать интерфейс Serializable.

"JSR 220: Enterprise JavaBeansTM, версия 3.0 API персистентности Java версии 3.0, финальная версия 2 мая 2006 г."

Вам нужны ваши сущности, чтобы быть Serializable если вам нужно передать их по проводам (сериализовать их в другое представление), сохраните их в сеансе http (который, в свою очередь, сериализуется на жесткий диск контейнером сервлета) и т. д.

Просто ради настойчивости, Serializable не нужен, по крайней мере с Hibernate. Но это лучшая практика, чтобы сделать их Serializable,

Согласно документам спящего режима при использовании аннотации @JoinColumn:

У него есть еще один параметр с именем referencedColumnName, Этот параметр объявляет столбец в целевом объекте, который будет использоваться для объединения. Обратите внимание, что при использовании referencedColumnName для столбца без первичного ключа связанный класс должен быть Serializable,

Спецификация JPA

Согласно спецификации JPA, объект должен реализовывать Serializable только если его необходимо передать от одной JVM к другой или если объект используется сеансовым компонентом с отслеживанием состояния, который должен быть пассивирован контейнером EJB.

Если экземпляр сущности должен быть передан по значению как отдельный объект (например, через удаленный интерфейс), класс сущности должен реализовывать Serializable интерфейс.

Спящий режим

Hibernate требует только атрибутов сущности Serializable, но не сам объект.

Однако при реализации спецификации JPA все требования JPA в отношении Serializable сущности также применимы к Hibernate.

Кот

Согласно документации Tomcat,HttpSession атрибуты также должны быть Serializable:

Каждый раз, когда Apache Tomcat завершается в обычном режиме и перезапускается, или когда запускается перезагрузка приложения, стандартная реализация Manager будет пытаться сериализовать все текущие активные сеансы в файл на диске, расположенный с помощью атрибута pathname. Все такие сохраненные сеансы затем будут десериализованы и активированы (при условии, что они не истекли за это время), когда перезагрузка приложения будет завершена.

Чтобы успешно восстановить состояние атрибутов сеанса, все такие атрибуты ДОЛЖНЫ реализовывать интерфейс java.io.Serializable.

Итак, если сущность хранится в HttpSession, он должен реализовать Serializable.

Если мы просто поговорим о настойчивости, Serializable не требуется, но лучше всего делать объекты Serializable,

Если мы выставляем domain / entities объекты, непосредственно представленные на уровне представления, вместо использования DTO В таком случае нам нужно реализовать Serializable , Эти доменные объекты могут храниться в HTTPSession для целей кэширования / оптимизации. Http-сессия может быть сериализована или сгруппирована. И это также требуется для передачи данных между JVM -instances.

Когда мы используем DTO отделить персистентный слой и сервисный уровень, помечая доменные объекты как Serializable будет контрпродуктивным и нарушит encapsulation ". Тогда это становится анти-паттерном.

Составные идентификаторы

Класс первичного ключа должен быть сериализуемым.

POJO Модели

Если экземпляр сущности должен использоваться удаленно как отдельный объект, класс сущности должен реализовать Serializable интерфейс.

кэш
Кроме того, если вы реализуете clustered второй уровень cache тогда ваши сущности должны быть serializable, Идентификатор должен быть Serializable потому что это требование JPA, так как identifier может быть использован в качестве ключа для записи в кэш второго уровня.

И когда мы сериализуем сущности, убедитесь, что предоставили явные serialVersionUID с модификатором частного доступа. Потому что если serializable класс явно не объявляет serialVersionUID тогда во время выполнения сериализации будет вычислено значение по умолчанию serialVersionUID значение для этого класса, основанное на различных аспектах класса, как описано в Спецификации Сериализации Объекта Java(TM). По умолчанию serialVersionUID вычисления очень чувствительны к деталям класса, которые могут варьироваться в зависимости от реализации компилятора, и, следовательно, могут привести к неожиданным InvalidClassExceptions во время десериализации.

Я считаю, что ваша проблема связана с наличием поля сложного типа (класса), которое не аннотировано. В таких случаях обработка по умолчанию будет хранить объект в его сериализованной форме в базе данных (что, вероятно, не то, что вы хотели сделать) Пример:

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

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

В приведенном выше случае CustomerData будет сохранен в поле байтового массива в базе данных в его сериализованной форме.

В дополнение к приятному ответу Конора, который ссылался на спецификации JSR-317. Как правило, проекты EAR состоят из модуля EJB с EJB, предоставляемыми через удаленный интерфейс. В этом одном случае вам нужно сделать сериализованные бины сущностей такими, как они агрегированы в удаленном EJB-компоненте и построены для передачи по сети.

Военный проект JEE6 без CDI: может содержать EJB lite, поддерживаемый несериализуемыми сущностями JPA.

Военный проект JEE6 с CDI: Бины, использующие область сеанса, приложения или диалога, должны быть сериализуемыми, но бины, использующие область запроса, не должны быть сериализуемыми. Таким образом, базовые бины сущности JPA -if any- будут следовать той же семантике.

Пожалуйста, обратитесь к http://www.adam-bien.com/roller/abien/entry/do_jpa_entities_have_to сказано: "Реализация java.io.Serializable просто необходима для передачи данных через IIOP или JRMP (RMI) между экземплярами JVM. В случае чистого веб-приложения доменные объекты иногда хранятся в HTTPSession для целей кэширования / оптимизации. Http-сессия может быть сериализована (пассивироваться) или кластеризована. В обоих случаях весь контент должен быть сериализуемым.

Классы должны реализовывать Serializable, если вы хотите их сериализовать. Это не имеет прямого отношения к JPA, и спецификация JPA не требует, чтобы объекты были сериализуемыми. Если Hibernate действительно жалуется на это, я предполагаю, что это ошибка Hibernate, но я предполагаю, что вы прямо или косвенно делаете что-то еще с объектами, которые требуют их сериализации.

  1. В какой момент становится необходимым сделать сериализованную мою сущность?

Реализация ehcache с хранилищем дисков в качестве кэша второго уровня (т.е. с использованием @Cacheable для аннотации объекта или метода репозитория / службы) требуется Serializable, в противном случае кэш завершится с ошибкой (NotSerializableException) записать сущность в дисковый кеш.

Когда объекты JPA используются в качестве параметров или возвращаемых значений удаленными операциями EJB

Удаленное попадание с использованием почтальона или ajax или углового js и т. д......, может вызвать цикл повторения с исключением Stackru с Джексоном fastxml. Так что лучше использовать сериализатор.

Это также ошибка, которая выдается, когда вы передаете неверно введенный идентификатор в качестве второго параметра чему-то вроде em.find() (т.е. передаете сам объект, а не его идентификатор). Я пока не счел необходимым фактически объявлять сущности JPA сериализуемыми - это на самом деле не нужно, если вы не используете referencedColumnName, как описано aman.

Другие вопросы по тегам