-
카테고리
-
세부 분야
백엔드
-
해결 여부
미해결
Repository, Service에 따른 , @Transaction(readOnly=ture)에 따른 쿼리 차이에 대해 질문드립니다.
22.05.12 22:22 작성 조회수 409
0
@Entity
@Getter @Setter
public class Category {
@Id @Column(name="CATEGORY_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="MEMBER_ID")
private Member member;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="PARENT_ID")
private Category parent;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Category> child = new ArrayList<>();
}
@Repository
public class CategoryRepository {
private final EntityManager em;
public List<Category> findAll(){
return em.createQuery("select c from Category c", Category.class)
.getResultList();
}
}
@Service
@Transactional
@RequiredArgsConstructor
public class CategoryService {
private final CategoryRepository categoryRepository;
@Transaction <-- 이부분
//@Transaction(readOnly=true) <-- 이부분
public List<Category> findAll() {return categoryRepository.findAll(); }
}
@RestController
@RequiredArgsConstructor
public class CategoryApiController {
private final CategoryService categoryService;
private final CategoryRepository categoryRepository;
private final MemberService memberService;
@GetMapping("/api/v1/categories")
public Result getCategory(@RequestParam(required = false, value = "id") String memberId){
List<Category> categories = categoryService.findAll(); <-- 이부분
// List<Category> categories = categoryRepository.findAll(); <-- 이부분
List<CategoryDto> categoryDtos = categories.stream()
.map(c -> new CategoryDto(c))
.collect(Collectors.toList());
return new Result(categoryDtos.size(), categoryDtos);
}
@Data
@AllArgsConstructor
static class CategoryDto{
public CategoryDto(Long id, String name) {
this.id = id;
this.name = name;
}
public CategoryDto(Category category) {
this.id = category.getId();
this.name = category.getName();
this.child = category.getChild().stream()
.map(c -> new CategoryDto(c.getId(),c.getName()))
.collect(Collectors.toList());
}
private Long id;
private String name;
private List<CategoryDto> child;
private Long parentId;
}
}
- categoryRepository.findAll()를 호출 했을 때
2022-05-12 23:35:46.474 DEBUG 18928 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2022-05-12 23:35:46.527 INFO 18928 --- [nio-9090-exec-2] p6spy : #1652366146527 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_
select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_;
2022-05-12 23:35:46.539 INFO 18928 --- [nio-9090-exec-2] p6spy : #1652366146539 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (?, ?, ?, ?, ?, ?, ?, ?)
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (6, 7, 8, 9, 10, 11, 12, 13);
2022-05-12 23:35:46.566 DEBUG 18928 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
- categoryService.findAll() 을 호출 했을 때
1)@Transaction(readOnly = true)
2022-05-12 23:31:45.235 DEBUG 18388 --- [nio-9090-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2022-05-12 23:31:45.258 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(72969494<open>)] for JPA transaction
2022-05-12 23:31:45.258 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.blog.demo.service.CategoryService.findAllRootCategories]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
2022-05-12 23:31:45.261 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@675de2b1]
2022-05-12 23:31:45.292 INFO 18388 --- [nio-9090-exec-1] p6spy : #1652365905292 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_
select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_;
2022-05-12 23:31:45.301 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2022-05-12 23:31:45.301 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(72969494<open>)]
2022-05-12 23:31:45.301 INFO 18388 --- [nio-9090-exec-1] p6spy : #1652365905301 | took 0ms | commit | connection 1| url jdbc:h2:tcp://localhost/~/blog
;
2022-05-12 23:31:45.302 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
2022-05-12 23:31:45.303 INFO 18388 --- [nio-9090-exec-1] p6spy : #1652365905303 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (?, ?, ?, ?, ?, ?, ?, ?)
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (6, 7, 8, 9, 10, 11, 12, 13);
2022-05-12 23:31:45.329 DEBUG 18388 --- [nio-9090-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2)@Transaction
2022-05-12 23:37:14.348 DEBUG 19206 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2022-05-12 23:37:14.369 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1468362384<open>)] for JPA transaction
2022-05-12 23:37:14.369 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.blog.demo.service.CategoryService.findAllRootCategories]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2022-05-12 23:37:14.371 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@4209a22e]
2022-05-12 23:37:14.402 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234402 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_
select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_;
2022-05-12 23:37:14.414 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2022-05-12 23:37:14.414 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1468362384<open>)]
2022-05-12 23:37:14.418 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234418 | took 0ms | commit | connection 1| url jdbc:h2:tcp://localhost/~/blog
;
2022-05-12 23:37:14.419 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
2022-05-12 23:37:14.420 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234420 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=6;
2022-05-12 23:37:14.421 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234421 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=7;
2022-05-12 23:37:14.423 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234423 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=8;
2022-05-12 23:37:14.424 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234424 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=9;
2022-05-12 23:37:14.424 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234424 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=10;
2022-05-12 23:37:14.424 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234424 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=11;
2022-05-12 23:37:14.425 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234425 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=12;
2022-05-12 23:37:14.425 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234425 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=?
select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=13;
2022-05-12 23:37:14.456 DEBUG 19206 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
안녕하세요. 좋은 강의 감사합니다.
강의에서 Order로 api를 만들어주셔서 저는 개인적으로 Category에 대해서 api를 간단하게 만들어보면서 테스트를 몇가지 진행했었는데요.
Controller에서 Category의 child를 지연로딩을 통해서 가져올 때 아래 세가지의 경우에 따라 쿼리문이 달라지는 현상을 겪었습니다. 위 코드에서 `<-- 이부분` 으로 표시된 부분을 참고해주시면 감사하겠습니다.
1. Repository로 최초에 Category를 가져올 때에는 in 쿼리가 잘 나갔고,
2. Controller에서 Service로 최초에 Category를 가져올 때는 Service의 해당 메소드에 @Transaction 일떄에는 N+1 문제가 발생하고
3. readOnly=true 일때에는 in 쿼리로 잘 가지고 오는데
이 상황에대해서 이해가 잘 되지 않아 질문 드리게 됐습니다.
3가지 상황 모두 OSIV가 켜져있고, default_batch_fetch_size: 100인 상황입니다.
각각 상황에 대해서 왜 in 쿼리가 나가고 안나가는지에 대해서 설명해주실 수 있을까요? 감사합니다.
Repository와 Service차이의 경우 OSIV가 켜져있기 때문에 Controller에 돌아와서도 영속성 컨텍스트가 유지되는게 동일 할텐데 왜 쿼리 차이가 있는지 모르겠고
readOnly=true인 경우, 영속성 컨텍스트의 내용을 플러시하지 않는 것으로 알고있는데 플러시 여부와 지연로딩시 쿼리가 다르게 나가는 것은 상관이 없을 것 같은데 왜 차이가 나는지 파악이 안되고 있습니다.
* 트랜잭션 로그를 찍어보니 Repository에서는 transaction을 생성하지 않고 트랜잭션없는 읽기를 진행하는 것으로 보이고 Service에서는 readOnly인 트랜잭션을 생성하냐/아니냐의 차이로 보입니다.
답변을 작성해보세요.
0
답변 1