일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- gradle
- 빌드툴
- exception
- String
- FunctionalInterfaces
- beanfactory
- 토비의스프링3.1
- Kotlin for Java Developers
- JPA
- ApplicationContext
- 토비의스프링
- 자바
- lambda
- DispatcherServlet
- springboot
- 클린코드
- 링킹
- Immutable
- 프록시
- AutoConfiguration
- DesignPattern
- java
- 컴퓨터시스템
- ORM
- IOC
- 메이븐
- 링커
- springwebmvc
- hibernate
- Spring
- Today
- Total
엔지니어로 가는 길
HibernateException: Illegal attempt to associate a collection with two open sessions 원인과 해결방법 본문
HibernateException: Illegal attempt to associate a collection with two open sessions 원인과 해결방법
탐p슨 2021. 7. 14. 19:42흔히 접할 수 있는 에러는 아닌 것 같다. 그런데 흔하지 않은 상황이 닥쳐서 이 에러를 만났고, 에러의 원인을 찾고 해결하기 위해 구글링했으나 쉽게 답을 못찾다가 이해할만한 답을 찾아냈다.
This occurs because we are using a different Hibernate session to find or create inventory items associated with the incoming stock. The inventory item cannot be associated with both sessions at the same time. It might be as easy as flushing the temporary session, but I need to investigate further.
https://github.com/openboxes/openboxes/issues/50
말 그대로 두 개의 Session에서 같은 collection을 다루려고 할 때 발생하는 에러이다. 여기서 힌트를 얻어 어떨 때 이런 에러가 발생하는지를 재현할 수 있었다.
문제 상황
환경: kotlin + hibernate + gradle(allOpen, noArg 플러그인 적용)
Book과 Author는 문제 상황을 재현하기 위해 만든 간단한 엔티티 클래스이다. 양방향으로 매핑되어 있는데 여기서 주목해야하는 부분은 Author의 books라는 collection 필드이다.
두 개의 세션(bookRepo와 authorRepo)을 연다.
bookRepo라는 Session에서는 book을 1차 캐시에 가지고 있다.
authorRepo라는 Session에서는 author를 1차 캐시에 가지고 있다.
* 정확히는 author라는 Author 객체에 books라는 collection을 가지고 있다는 점이 중요하다. 이 예외는 collection을 두 개의 Session에서 접근할 때 에러가 발생하기 때문이다.
bookRepo에서 author를 save하려고 하면, 이미 authorRepo에서 author(books라는 collection)를 가지고 있기 때문에 예외가 발생한다.
Exception in thread "main" org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions. Collection : [Author.books#2]
문제 상황을 가장 간단하게 재현하기 위해 만든 예시라서 억지스럽다. authorRepo를 두고 bookRepo에서 author를 save할 이유가 없기 때문이다. 그나마 조금 자연스러운 경우는 아래와 같이 Book 클래스에서 Author를 cascade 옵션을 이용하여 영속성을 전이시키는 경우이다. (생각해보니 Many가 One에게 cascade 하는 게 자연스러운가 싶은데 지금 문제는 이게 아니므로..)
book에 Author 객체를 넣어주고 book을 save 하려고 시도하는데 영속성 전이가 설정되어 있기 때문에 book 뿐만 아니라, Author까지 영속을 관리하려고 시도하여 아까와 같은 이유로 예외가 발생한다.
해결 방법
Repository 객체를 생성할 때마다 Session을 만들어 사용하는 경우라면 이 예외를 만날 수 있는데, 위의 상황과 같이 한 로직 안에서 여러 Repository 객체를 사용해야만 하는 경우 cascade 옵션을 주의해서 사용하거나, Session을 적절히 clear()하여 1차 캐시를 비우면 예외를 피할 수 있다.
.. 이런 예외를 만나는 게 더 어려울 것 같지만 만약 만날 경우 드문 예외인 만큼 헤맬 수도 있으므로 일단 기록해둔다.
'프로그래밍 > ORM' 카테고리의 다른 글
hibernate.hbm2ddl-auto 옵션이 제대로 동작하지 않을 때 (0) | 2021.07.07 |
---|---|
ORM이란 무엇이며 어떤 문제를 해결하는가 (0) | 2021.05.31 |