티스토리 뷰
출처 : https://www.baeldung.com/hibernate-lazy-loading-workaround
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true의 의미가 무얼까?
1. Overview
While using lazy loading in Hibernate, we might face exceptions, saying there is no session.
In this tutorial, we'll discuss how to solve these lazy loading issues. To do this, we'll use Spring Boot to explore an example.
2. Lazy Loading Issues
The aim of lazy loading is to save resources by not loading related objects into memory when we load the main object. Instead, we postpone the initialization of lazy entities until the moment they're needed. Hibernate uses proxies and collection wrappers to implement lazy loading.
When retrieving lazily-loaded data, there are two steps in the process. First, there's populating the main object, and second, retrieving the data within its proxies. Loading data always requires an open Session in Hibernate.
The problem arises when the second step happens after the transaction has closed, which leads to a LazyInitializationException.
The recommended approach is to design our application to ensure that data retrieval happens in a single transaction. But, this can sometimes be difficult when using a lazy entity in another part of the code that is unable to determine what has or hasn't been loaded.
Hibernate has a workaround, an enable_lazy_load_no_trans property. Turning this on means that each fetch of a lazy entity will open a temporary session and run inside a separate transaction.
이 property를 true로 하는 것은 lazy entity를 가져올 때 임시session을 여는 것이다. 구별된 transaction에서 실행된다.
3. Lazy Loading Example
3.1 Set Up Entities and Services
@Entity
public class User {
// other fields are omitted for brevity
@OneToMany(mappedBy = "userId")
@Fetch(FetchMode.SUBSELECT)
private List<Document> docs = new ArrayList<>();
}
@Service
public class ServiceLayer {
@Autowired
private UserRepository userRepository;
@Transactional(readOnly = true)
public long countAllDocsTransactional() {
return countAllDocs();
}
public long countAllDocsNonTransactional() {
return countAllDocs();
}
private long countAllDocs() {
return userRepository.findAll()
.stream()
.map(User::getDocs)
.mapToLong(Collection::size)
.sum();
}
}
3.2. Lazy Loading With a Surrounding Transaction
@Test
public void whenCallTransactionalMethodWithPropertyOff_thenTestPass() {
SQLStatementCountValidator.reset();
long docsCount = serviceLayer.countAllDocsTransactional();
assertEquals(EXPECTED_DOCS_COLLECTION_SIZE, docsCount);
SQLStatementCountValidator.assertSelectCount(2);
}
3.3. Lazy Loading Outside of a Transaction
@Test(expected = LazyInitializationException.class)
public void whenCallNonTransactionalMethodWithPropertyOff_thenThrowException() {
serviceLayer.countAllDocsNonTransactional();
}
As predicted, this results in an error as the getDocs function of User is used outside of a transaction.
예상한 바와 같이 transaction 밖에서 User.getDocs()호출시에 LazyInitializationException에러가 발생한다.
3.4. Lazy Loading With Automatic Transaction
에러를 제거하기 위해 다음 property를 설정하면 더이상 LazyInitializationException에러가 발생하지는 않는다.
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
@Test
public void whenCallNonTransactionalMethodWithPropertyOn_thenGetNplusOne() {
SQLStatementCountValidator.reset();
long docsCount = serviceLayer.countAllDocsNonTransactional();
assertEquals(EXPECTED_DOCS_COLLECTION_SIZE, docsCount);
SQLStatementCountValidator.assertSelectCount(EXPECTED_USERS_COUNT + 1);
}
그러나, 한가지 알고 있어야 하는 것은.. 사용자가 5명일 경우,
위 3.2와 같이 transaction안에서 하면 2회(USER, DOCUMENT) DB에 접속(roundtrips)하지만, enable_lazy_load_no_trans=true 설정시에 DB query를 6회수행한다는 것이다. 1회 USER접근, 5명의 USER마다 DOCUMENT를 1회씩 총 6회 접근한다.
We've run into the notorious N + 1 issue
악명높은 N + 1에 빠지게 된다.
'Skill > JPA' 카테고리의 다른 글
eclipse로 DB table에서 Entity(vo)클래스 만들기 (0) | 2021.01.18 |
---|---|
[JPA] Querydsl 1분주기 데이터 중 10분 데이터 가져오기 (0) | 2020.09.22 |
[JPA] DB에 없는 필드 관련 (0) | 2020.08.14 |
[JPA] Open Session In View (0) | 2020.06.26 |
[JPA] MessageConverterConfiguration 적용시 에러 (0) | 2020.06.26 |
- Total
- Today
- Yesterday
- JQuery
- $.each
- object key
- element위치
- ul li로 테이블
- draw.io
- lombok
- 여러 컬럼 update
- devtools
- Keycode
- excel
- border-collapse
- springboot
- 진열사랑
- 프로젝트명변경
- DatePicker
- getter
- @ExceptionHandler
- oracle
- PostgreSQL
- setter
- QueryDSL
- 전후방탐색
- caniuse
- Javascript
- CSS
- spring
- 정규식
- $.extend
- sumifs
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |