#java #hibernate #jpa #orm #spring-data
#java #спящий режим #jpa #orm #spring-данные
Вопрос:
У меня есть история, содержащая список комментариев, сопоставленный с таблицей соединений. Я заметил, что каждый раз, когда я добавляю новый комментарий в список, hibernate удаляет и воссоздает все записи в таблице соединений, связанные с историей. Я бы ожидал, что он просто добавит новую строку в таблицу. В приведенном ниже коде методы сохранения реализованы Spring Data. Я что-то упускаю? Спасибо.
Story.java:
@Entity
public class Story implements Serializable {
@OneToMany
@JoinTable(name="UserComment", joinColumns = @JoinColumn(name = "Story_id"), inverseJoinColumns = @JoinColumn(name = "Comment_id"))
private List<Comment> userComments;
...
Comment.java:
@Entity
public class Comment implements Serializable {
...
Добавление нового комментария:
Comment comment = new Comment();
comment.setContent(content);
commentRepository.save(comment);
story.getUserComments().add(comment);
storyRepository.save(story);
Войдите в систему Hibernate при выполнении storyRepository.save(история):
Hibernate: delete from UserComment where Story_id=?
Hibernate: insert into UserComment (Story_id, Comment_id) values (?, ?)
Hibernate: insert into UserComment (Story_id, Comment_id) values (?, ?)
Hibernate: insert into UserComment (Story_id, Comment_id) values (?, ?)
Hibernate: insert into UserComment (Story_id, Comment_id) values (?, ?)
Hibernate: insert into UserComment (Story_id, Comment_id) values (?, ?)
Hibernate: insert into UserComment (Story_id, Comment_id) values (?, ?)
Hibernate: insert into UserComment (Story_id, Comment_id) values (?, ?)
Версии библиотеки:
- Спящий режим 4.3.5
- Spring Data JPA 1.6.0
Ответ №1:
Это ожидаемое поведение для используемого однонаправленного пакета. В соответствии с [Антишаблонами гибернации][1]:
Семантика bag имеет наихудшую производительность, когда дело доходит до количества операций, поскольку она всегда воссоздает всю коллекцию. Hibernate выдает инструкцию delete, чтобы удалить все ассоциации старой коллекции из таблицы ассоциаций. Затем он выдает N вставок, чтобы добавить все ассоциации, представляющие новую коллекцию, в таблицу ассоциаций. Hibernate не анализирует, сколько элементов было изменено в коллекции.
- Вы можете оптимизировать ее, превратив в id-bag, который представляет собой индексированный список.
- Вы можете сопоставить сопоставление UserComment, имеющее 2 ассоциации @ManyToOne, как с историей, так и с комментарием, так что ваш пакет превратится в двунаправленный пакет mappedBy, который намного эффективнее своего однонаправленного аналога (потому что пакет mappedBy не будет контролировать ассоциацию, поскольку именно сторона @ManyToOne будет распространять переходы состояний в операторы SQL).
Комментарии:
1. Я единственный, кто думает, что с таким количеством ошибок нам должно быть лучше без ассоциаций, управляемых hibernate? Я собираюсь написать простой собственный запрос, чтобы добавить комментарий к списку.
2. Мой совет — сделать это просто.
3. Как бы просто ни было написать мой собственный запрос, почему я должен менять свою модель, чтобы адаптироваться к особенностям механизма сохранения? @Query(значение=»вставить в UserComment (Story_id, Comment_id) ЗНАЧЕНИЯ (:Story_id, :commentId)», NativeQuery = true)
4. Это был общий совет. Собственный запрос будет работать, но он потребует изменения всякий раз, когда вы добавляете новое поле. Использование двунаправленной ассоциации является простым и более гибким. Но для этого требуется изменение сопоставления.