inflearn logo
강의

Khóa học

Chia sẻ kiến thức

Trong thực tế! Spring Boot và JPA Usage 2 - Phát triển API và tối ưu hóa hiệu suất

failed to lazily initialize a collection of role 오류 관련 문의

20751

gabozanet1044

17 câu hỏi đã được viết

4

안녕하세요. 항상 친절하고 정확한 답변 감사합니다.

지금 작업하다가 발생한 오류로 헤매고 있어서 질문드립니다.

소셜로그인으로 로그인 시 기존 회원정보가 없으면 생성하고 나서 소셜로그인 정보 생성하고,

기존 회원정보 있으면 해당 회원정보로 소셜로그인 정보를 생성하려고 합니다. (MemberService.java)

기존에 없는 회원일때 회원정보 생성하고 나서 소셜로그인 정보 생성하는건 잘 되는데,

이미 있는 경우에 기존회원정보를 member에 담아놓고 그걸로 소셜로그인 정보 생성할때 아래와 같은 오류가 발생합니다.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: kr.soleo.mall.base.domain.member.entity.Member.memberSocialProfiles, could not initialize proxy - no

...

수업들은거 잘 생각해서 구현했다고 생각했는데, 무슨 이유인지 모르겠네요. ㅠㅠ

Member.java

@Entity
@Table(name = "member")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "email", "username", "age"})
public class Member extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_id")
private Long id;

private String email;
private String password;
private String username;
private int age;

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
List<MemberAuth> memberAuths = new ArrayList<>();

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
List<MemberSocialProfile> memberSocialProfiles = new ArrayList<>();

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
List<Board> boards = new ArrayList<>();

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;

public Member(String username) {
this(username, 0);
}

public Member(String username, int age) {
this(username, age, null);
}

public Member(String username, int age, Team team) {
this.username = username;
this.age = age;
if (team != null) {
changeTeam(team);
}
}

//연관관계 메쏘드
public void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}

@Builder
public Member(String email, String password, String username, int age, Team team) {
this.email = email;
this.password = password;
this.username = username;
this.age = age;
if (team != null) {
changeTeam(team);
}
}

}

MemberSocialProfile.java

@Entity
@Table(name = "member_social_profile")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MemberSocialProfile extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_social_profile_id")
private Long id;

private String identifier; //소셜로그인시 id
private String photourl; //소셜로그인시 프사이미지 URL
private String email;

@Enumerated(EnumType.STRING)
private SocialType socialType; //facebook, kakao, google, naver

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;

//연관관계 메쏘드
public void changeMember(Member member) {
this.member = member;
member.getMemberSocialProfiles().add(this);
}

@Builder
public MemberSocialProfile(SocialType socialType, String identifier, String photourl, String email, Member member) {
this.socialType = socialType;
this.identifier = identifier;
this.photourl = photourl;
this.email = email;
if (member != null) {
changeMember(member);
}
}
}

MemberService.java

@Service
//@RequiredArgsConstructor
@Component
@Configurable
public class MemberService implements UserDetailsService {
@Autowired
private MemberRepository memberRepository;
@Autowired
private MemberAuthRepository memberAuthRepository;
@Autowired
private MemberSocialProfilesRepository memberSocialProfilesRepository;
@Autowired
private PasswordEncoder passwordEncoder;

@Transactional
public void createSocialAccount(MemberDto account) throws Exception {
Member member = null;
if (memberRepository.existsByEmail(account.getEmail())) { //1) member에 해당 이메일로 회원정보가 있으면 그 정보 이용해서 소셜정보생성
member = memberRepository.findByEmail(account.getEmail());

} else { //2) member에 해당 이메일로 회원정보가 없으면 회원정보 생성하고 소셜정보 생성

account.setPassword(passwordEncoder.encode(account.getPassword()));
member = Member.builder()
.email(account.getEmail())
.password(account.getPassword())
.username(account.getUsername())
.build();
memberRepository.saveAndFlush(member);

memberAuthRepository.saveAndFlush(
MemberAuth.builder()
.authType(AuthType.USER)
.member(member)
.build()
);
}

// 1) 조건인 경우 오류발생, 2) 조건인 경우 정상 저장 완료
memberSocialProfilesRepository.saveAndFlush(
MemberSocialProfile.builder()
.identifier(account.getIdentifier())
.photourl(account.getPhotourl())
.email(account.getEmail())
.socialType(account.getSocialType())
.member(member)
.build()
);
}

}

spring-boot java spring JPA

Câu trả lời 3

7

yh

안녕하세요. 조호영님^^

org.hibernate.LazyInitializationException 이 오류는 member를 조회까지는 성공했는데, member.get MemberSocialProfiles() 를 호출해서 사용할 때 영속성 컨텍스트가 종료되어 버려서, 지연 로딩을 할 수 없어서 발생하는 오류 입니다. JPA에서 지연로딩을 하려면 항상 영속성 컨텍스트가 있어야 하거든요.

보통 트랜잭션 밖에서 member를 조회하면 이런 문제가 발생합니다. 그런데 현재 코드만 보면 트랜잭션 안에서 조회한 것 처럼 보입니다. 트랜잭션이 해당 서비스에서 정상 처리 되는지 먼저 확인해보시겠어요?

그래도 잘 안되면, 동작하는, 그리고 실패하는 테스트 코드를 작성해서 전체 프로젝트를 압축해서 올려주세요.

감사합니다.

0

pjs01023034972

와.. 구글링하다 여기까지 왔는데 아무리 찾아봐도 fetch를 eager로 변경하라는 답변밖에 없었는데

@Transactional로 한방에 해결되었네요.

0

gahan1

와...  안녕하세요 구글링하다 이 글에 왔는데

'사용할 때 영속성 컨텍스트가 종료되어 버려서, 지연 로딩을 할 수 없어서 발생하는 오류 입니다.'

에 힌트를 얻어 제가 가지고있던 문제 해결에 성공했습니다!

감사 인사를 여기에라도 남깁니다. 좋은 하루 되세요!

3

gabozanet1044

안녕하세요. 답변 감사합니다.

트랜잭션 말씀하셔서 소스 다시 봤더니 createSocialAccount 메쏘드에는 @Transaction 어노테이션 적용했는데 저걸 호출하는 메쏘드에는 안했네요. 이부분 추가했더니 정상 처리됩니다.

@Transactional  // <-- 이부분이 없었어요.
public void setOauth2Member(MemberDto account) throws Exception {
memberSocialProfile = memberSocialProfilesRepository.findByIdentifier(account.getIdentifier());
if(memberSocialProfile == null) {
createSocialAccount(account);
}

}

그런데 이해가 안가는게, 위 호출부분에 @Transaction 없었을때,  질문과 같이 한번 생성은 되고 이후에 오류가 났는데 안되려면 초기 생성도 안되어야 하는거 아닌가요? 

0

yh

안녕하세요. 호형님

코드가 조각조각 되어 있어서, 분석하기가 쉽지 않네요^^;

테스트 할 수 있는 테스트 케이스를 만들고 코드를 압축해서

전체 프로젝트를 압축해서 올려주세요.

강의 관련 외 질문입니다.

0

62

2

SpringBoot4 + Hibernate7 모듈 등록 방법 공유

0

85

1

BeanCreationException

0

86

3

Update 후 UpdateMemberResponse 매핑할 때

0

46

1

트랜잭션을 사용 안 할 때 커넥션은 언제 가져오나요?

0

96

2

페이징 + 검색조건 관련해서 질문드립니다.

0

70

1

Query Dsl Q파일 질문입니다.

0

81

1

루트 쿼리라는것은

0

58

1

메서드를 분리하는 기준

0

61

1

findAllWithMemberDelivery 메서드 질문드립니다.

0

108

3

연관관계 매핑을 안 쓸 경우, 사용해야 하는 전략

0

83

2

fetch join과 영속화와 OSIV의 관계

0

83

2

Distinct 사용 전 결과에 대한 의문

0

112

2

레포지토리 계층에서의 트랜잭션에 대한 의문

0

55

1

영속성 컨텍스트 생명주기의 신기한 부분이 있습니다.

0

77

2

dto 필드 속 엔티티 여부

0

58

1

뷰템플릿 사용 시

0

76

2

Result 클래스 관련 질문

0

56

1

@PostConstruct 프록시 관련 질문드립니다

0

85

1

DTO 대신 Form 사용은 안되나요?

0

133

1

OSIV ON 상태일 때

0

94

1

fetch join VS fetch join 페이징 궁금증

0

179

2

양방향 연관관계 알아보는 법?

0

103

1

16강 17강 간단 정리 이게 맞을까요 ?

0

161

2