Hibernate генерирует дополнительный запрос во множестве отношений, пока не установлен CascadeType.REMOVE

#java #spring #hibernate #jpa #spring-security

#java #spring #переход в спящий режим #jpa #spring-безопасность

Вопрос:

У меня есть объект User :

 @Entity
@Table(name = "users")
public class User {
    (...)
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "users_roles",
            joinColumns = @JoinColumn(name = "user_id", nullable = false),
            inverseJoinColumns = @JoinColumn(name = "role_id", nullable = false)
    )
    private List<Role> roles;
}
  

и объект Role с простыми id и name столбцами.

User и Role имеет отношение многие ко многим с таблицей объединения users_roles .

Я создал метод для удаления пользователя:

 public void remove(long userId) {
    Session session = getSession();

    //NativeQuery joinTableQuery = session.createNativeQuery("DELETE FROM users_roles ur WHERE ur.user_id = :userId");
    //joinTableQuery.setParameter("userId", userId);
    //joinTableQuery.executeUpdate();

    Query userQuery = session.createQuery("DELETE FROM User u WHERE u.id = :userId");
    userQuery.setParameter("userId", userId);
    userQuery.executeUpdate();
}
  

Я специально закомментировал первый NativeQuery, чтобы проверить, что произойдет. И что интересно, теперь Hibernate генерирует два запроса:

  • Hibernate: удалить из users_roles, где (user_id) в (выберите идентификатор из users, где id =?)
  • Hibernate: удалять из пользователей, где id =?

Вопрос:

Почему Hibernate генерирует дополнительный запрос к users_roles (join table), в то время как мой User объект не имеет отношения CascadeType.REMOVE set on @ManyToMany ? Я думал, что должен написать это сам (прокомментированная часть).

Ответ №1:

Вашей User сущности принадлежит связь «многие ко многим» с Role сущностью. Когда вы удаляете User , Hibernate автоматически также удаляет все записи из таблицы ассоциаций. Но это не каскадирует операцию удаления для Role объекта.

Вы никогда не должны использовать CascadeType.REMOVE для ассоциации «многие ко многим». Если вы удалите объект, Hibernate удалит все связанные объекты, даже если на них все еще ссылаются другие объекты. Я очень подробно объяснил это в своем блоге.

Если бы вы использовали CascadeType.REMOVE в своей roles ассоциации и удалили User , Hibernate удалил бы все Role объекты, на которые ссылается это User . Это будет сделано, даже если есть другие User объекты entity, которые связаны с этими Role объектами.