Когда и почему сущности JPA должны реализовывать интерфейс Serializable?
Вопрос в заголовке. Ниже я только что описал некоторые свои мысли и выводы.
Когда у меня была очень простая модель предметной области (3 таблицы без каких-либо отношений), все мои объекты НЕ реализовали Serializable.
Но когда модель предметной области стала более сложной, я получил RuntimeException, в котором говорилось, что одна из моих сущностей не реализовала Serializable.
Я использую Hibernate в качестве реализации JPA.
Я думаю:
- Это специфичное для поставщика требование / поведение?
- Что происходит с моими сериализуемыми объектами? Должны ли они быть сериализуемыми для хранения или передачи?
- В какой момент становится необходимым сделать сериализованную мою сущность?
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
". Тогда это становится анти-паттерном.
Класс первичного ключа должен быть сериализуемым.
Если экземпляр сущности должен использоваться удаленно как отдельный объект, класс сущности должен реализовать 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, но я предполагаю, что вы прямо или косвенно делаете что-то еще с объектами, которые требуют их сериализации.
- В какой момент становится необходимым сделать сериализованную мою сущность?
Реализация ehcache с хранилищем дисков в качестве кэша второго уровня (т.е. с использованием @Cacheable
для аннотации объекта или метода репозитория / службы) требуется Serializable, в противном случае кэш завершится с ошибкой (NotSerializableException
) записать сущность в дисковый кеш.
Когда объекты JPA используются в качестве параметров или возвращаемых значений удаленными операциями EJB
Удаленное попадание с использованием почтальона или ajax или углового js и т. д......, может вызвать цикл повторения с исключением Stackru с Джексоном fastxml. Так что лучше использовать сериализатор.
Это также ошибка, которая выдается, когда вы передаете неверно введенный идентификатор в качестве второго параметра чему-то вроде em.find() (т.е. передаете сам объект, а не его идентификатор). Я пока не счел необходимым фактически объявлять сущности JPA сериализуемыми - это на самом деле не нужно, если вы не используете referencedColumnName, как описано aman.