Можно ли принудительно сохранить сущность без персистентного контекста?
Что проверяют
Понимаете ли вы, что делает персистентный контекст, а не просто помните, что он есть. Вопрос обычно идёт после разговора про кэш первого уровня и грязную проверку, и ответ показывает, умеете ли вы писать пакетную запись, не воюя с ORM.
Как отвечать
Через EntityManager без контекста сохранить нельзя: persist и merge работают именно с ним, а создание нового EntityManager контекст не убирает, оно заводит новый. Так что ответ это не «да или нет», а перечень способов записать данные мимо контекста.
StatelessSessionв Hibernate. Нет кэша первого уровня, нет грязной проверки, нет каскадов и событий, операции вставки и обновления уходят в базу сразу. Подходит для миграций и массовой загрузки;- нативный запрос через
createNativeQueryиexecuteUpdate, а такжеJdbcTemplateили обычный JDBC; - Spring Data JDBC или jOOQ как слой, у которого персистентного контекста нет по устройству.
Если контекст всё же нужен, но мешает размером, лечится это не отказом от него, а вызовом flush вместе с clear через каждые несколько сотен сущностей и включённой пакетной вставкой.
Где спотыкаются
Считают, что merge сохраняет переданный объект. Он копирует состояние в управляемый экземпляр и возвращает его, а исходная ссылка остаётся отсоединённой, и дальнейшие правки по ней в базу не уедут.
Второе: обходя контекст, забывают, что он про такие изменения ничего не знает. Нативный UPDATE меняет строки в базе, а в кэше первого и второго уровня лежат прежние значения, и следующий find вернёт устаревшую сущность, пока не сделан clear или явная инвалидация.
Третье: путают закрытие контекста с потерей данных. Незакоммиченная транзакция откатится, это понятно, но по-настоящему больно бывает иначе: у отсоединённой сущности ленивые связи перестают подгружаться, и код падает на обращении к коллекции уже за пределами транзакции.