Spring/JPA

(JPA) could not initialize proxy - no Session (1)

주누 2022. 11. 19. 21:32

JPA를 사용하다 보면 아래 오류를 빈번하게 마주치게 된다.
could not initialize proxy - no Session​

해당 오류의 원인을 Open Session In View와 관련지어 정리해보고자 한다.
또한 영속성 컨텍스트의 시작과 종료 시 JPA 내부의 코드를 디버깅하여 정확히 살펴보고자 한다.


Example

예제는 Member와 Team 엔티티가 존재하고 Member가 Team으로 향하는 단방향 OneToMany 관계이다.

자세한 구조는 아래 접은 글을 참고하시길 바란다.

더보기

Diagram

Member

@Entity
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "member")
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    @Column(name = "name")
    private String name;

    @OneToMany(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "member_id")
    private Set<Team> teams;

}

Team

@Entity
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "team")
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "team_id")
    private Long id;

    @Column(name = "team_name")
    private String name;

}

 

Controller

@GetMapping("team/{id}")
public Set<Team> getTeam(@PathVariable Long id) {
    Set<Team> teams = teamService.getTeam(id);
    return teams;
}

Service

public Set<Team> getTeam(Long id) {
    Member member = memberRepository.findById(id)
            .orElseThrow();
    Set<Team> teams = member.getTeams();
    
    return teams;
}
해당 스켈레톤 코드를 바탕으로 OSIV를 적용하였을 때와 적용하였을 때를 구분하여 살펴보자!

Open Session In View를 적용하지 않았을 때

Configuration

open-in-view: false

Request

### Team 조회
GET http://localhost:8080/osiv/team/1
Accept: application/json

 

해당 요청을 진행하면 아래 에러가 발생한다.

 

Error

2022-11-16 21:42:27.300  WARN 19985 --- [nio-8080-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: co
m.example.blog.osiv.entity.Member.teams,
 could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: co
m.example.blog.osiv.entity.Member.teams,
 could not initialize proxy - no Session]
이유가 무엇일까?
이유는 Service 레이어에서 시작되었던 영속성 컨텍스트의 라이프 사이클이 Controller 레이어까지 이어지지 않았기 때문이다.

 

Open Session In View 가 설정되지 않으면 트랜잭션 시작 시점에 영속성 컨텍스트가 시작되어 트랜잭션이 종료되는 시점에 영속성 컨텍스트가 소멸되게 된다.

그렇기 때문에 Service 레이어에서 리턴 받은 값을 Controller에서 조회하는 과정에서 영속성 컨텍스트가 끊겼기 때문에 값을 가져올 수 없어 오류가 발생하는 것이다.

 

(@RestController로 인한 json 변환 시 teams 조회)


Open Session In View를 적용하였을 때

Configuration

open-in-view: true

Request

### Team 조회
GET http://localhost:8080/osiv/team/1
Accept: application/json

해당 요청을 진행하면 위와 달리 아래 에러가 발생하지 않는다.

이유가 무엇일까?
컨텍스트의 라이프 사이클이 요청 종료시점까지 소멸되지 않았기 때문이다.

 

Open Session In View 가 설정되면 컨트롤러 요청 시점에 영속성 컨텍스트가 시작되어 트랜잭션 종료시점에 영속성 컨텍스트가 소멸하지 않는다.

그렇기 때문에 Service 레이어에서 리턴 받은 값을 Controller에서 조회하는 과정에서 영속성 컨텍스트가 유지되기 때문에 값을 가져올 수 수 있어 위와 달리 에러가 발생하지 않는 것이다.

 


정리

OSIV 에 따라서 영속성 컨텍스트의 라이프 사이클이 달라진다.
OSIV 가 적용되면 요청시점 (DispatcherServlet 이후의 과정) 부터 요청 종료까지 영속성 컨텍스트의 라이프 사이클이 유지된다.
반면 OSIV 가 적용되지 않으면 영속성 컨텍스트의 라이프 사이클은 트랜잭션의 라이프 사이클과 함께한다.
그렇기 때문에 다음 레이어 까지 트랜잭션이 이어지지 않으면 영속성 컨텍스트가 종료되어 
could not initialize proxy - no Session

에러를 마주하게 된다.

다음 장에서는 영속성 컨텍스트의 생성 시점과 종료시점을 내부 코드를 통해 살펴보도록하자!

 


https://jwdeveloper.tistory.com/311

 

(JPA) could not initialize proxy - no Session (2)

영속성 컨텍스트 생성 OSIV 일 때 최초 요청 시 (컨트롤러 접근 시) 영속성 컨텍스트를 미리 생성한다. OSIV가 아닐 때 트랜잭션 요청 시 영속성 컨텍스트를 생성한다. OSIV 일때 인터셉터 영역에서

jwdeveloper.tistory.com

Code Link

https://github.com/mike6321/Blog/commit/106556c6d5350180303cf1e0b23d3ce2393b5478

 

feat : (OSIV) Writing Skeleton Code · mike6321/Blog@106556c

Show file tree Showing 12 changed files with 280 additions and 0 deletions.

github.com

https://github.com/mike6321/Blog/commit/4ba38e67e583daec37dfe76685068fd70c3165f0

 

feat : (OSIV) open session in view : true · mike6321/Blog@4ba38e6

Showing 1 changed file with 1 addition and 1 deletion.

github.com

https://github.com/mike6321/Blog/commit/2397e82577e8034c005bb141442d3449c41f2118

 

feat : (OSIV) non error (non transaction, open session in view : true) · mike6321/Blog@2397e82

Showing 1 changed file with 0 additions and 1 deletion.

github.com

https://github.com/mike6321/Blog/commit/4e60747a15d20be750060b4ccd1b2ea7f01650c7

 

feat : (OSIV) could not initialize proxy (non transaction, open sessi… · mike6321/Blog@4e60747

…on in view : false)

github.com