안녕하세요 개인 프로젝트중 궁금한게 생겨서 질문드립니다.
478
작성한 질문수 3
안녕하세요 선생님 스프링부트를 이용한 프로젝트를 진행중에 궁금한 것이 생겨서 꼭 알고 싶은 마음에 질문하게 되었습니다.
프로젝트 구성은 이렇습니다. Entity는 User, Board, Comment를 만들었고, Spring Data Jpa를 활용하여 각각의 repository인 UserRepository, BoardRepository, CommentRepository도 만들었고, service부분인 CommentServiceImpl을 구성하는 중에 문제가 발생하였습니다.
@Service
public class CommentServiceImpl implements CommentService{
...
@Override
public Long create(User user, Long board_id, String content) {
Board board = boardRepository.findById(board_id).get();
//user.getClass() = class com.graduation.parrot.domain.User //proxy가 아님을 확인
System.out.println("user.getClass() = " + user.getClass());
//user.getBoards() = [Board(id=2, title=title1, content=at), ... //정상실행
System.out.println("user.getBoards() = " + user.getBoards());
//LazyInitializationException 발생
System.out.println("user.getComments() = " + user.getComments());
return commentRepository.save(new Comment(content, user, board)).getId();
}
에러메시지 : org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.graduation.parrot.domain.User.comments, could not initialize proxy - no Session
원래는 System.out.print...이 부분이 없었지만 이해를 돕기위하여 추가하였습니다. (return 부분의 new Comment를 생성할때 생성자에서 user.getComments()가 실행됩니다.)
테이블의 연관관계 매핑은 [user : board - 1대다], [user : comment - 1대다], [board : comment - 1대다] 이렇게 구성하였습니다.
제가 생각할때 user.getBoards()와 user.getComments()가 구조상 차이가 없어보이는데 스프링은 그렇게 생각하지 않는지 user.getComments()를 실행할 때만 에러를 발생시킵니다..
문제상황 자체를 해결하는 방법은 찾았으나(user를 바로 사용하지 않고 userRepository.findById() 이용) 왜 user.getComments()만 문제가 발생하는지 꼭 알고 싶습니다.
+@Transactional를 달아도 에러가 발생합니다
아래는 Entity들의 자바코드입니다.
User
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "name", "login_id", "password"})
public class User extends BaseTimeEntity{
@Id
@GeneratedValue
@Column(name = "user_id")
private Long id;
@Column(nullable = false, length = 100, unique = true)
private String login_id;
@JsonIgnore
@Column(nullable = false, length = 100)
private String password;
@Column(length = 15, unique = true)
private String name;
@Column(length = 100)
private String email;
@Enumerated(EnumType.STRING)
private Role role = Role.ROLE_USER;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Board> boards = new ArrayList<>();
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
@Builder
public User(String login_id, String password, String name, String email) {
this.login_id = login_id;
this.password = password;
this.name = name;
this.email = email;
}
}
Board
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@ToString(of = {"id", "title", "content"})
public class Board extends BaseTimeEntity{
@Id
@GeneratedValue
@Column(name = "board_id")
private Long id;
@Column(nullable = false, length = 30)
private String title;
@Column(length = 1000)
private String content;
private String author;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", updatable = false)
private User user;
@OneToMany(mappedBy = "board", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
@Builder
public Board(String title, String content, User user) {
this.title = title;
this.content = content;
this.author = user.getName();
setUser(user);
}
public void setUser(User user) {
this.user = user;
user.getBoards().add(this);
}
Comment
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@ToString(of = {"id", "content"})
public class Comment extends BaseTimeEntity{
@Id @GeneratedValue
@Column(name = "comment_id")
private Long id;
@Column(nullable = false)
private String content;
private String author;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id")
private Board board;
@Builder
public Comment(String content, User user, Board board) {
this.content = content;
this.author = user.getName();
setUser(user);
setBoard(board);
this.board = board;
}
public void setUser(User user) {
this.user = user;
user.getComments().add(this); //System.out.print를 지우고 정상실행시 이 부분에서 지연로딩 에러가 발생합니다.
}
private void setBoard(Board board) {
this.board = board;
board.getComments().add(this);
}
}
답변 1
1
안녕하세요. 이호석님
모든 과정을 트랜잭션 안에서 처리해야 합니다.
현재 파라미터를 보면 create(User user)라는 부분을 확인할 수 있는데요.
User가 트랜잭션 밖에서 조회되고, 넘어온 것입니다.
이 문제를 해결하려면 user 자체를 트랜잭션 안에서 조회하셔야 합니다.
트랜잭션이 있는 서비스에서 user를 조회하시면 될꺼에요.
감사합니다.
changeTeam 메서드 질문
0
35
1
existsByUserIdAndProjectId vs existsByUserAndProject 중 어떤 방식이 적절할까요?
0
88
1
existsByUserIdAndProjectId vs existsByUserAndProject 중 어떤 방식이 적절할까요?
0
129
3
MemberRepository 구현체
0
73
1
pdf 표현 질문드립니다.
0
78
1
로그가 남지 않는 문제.
0
100
1
테스트 라이브러리가 강의는 junit4가 맞나요??
0
80
2
pdf 파일과 차이점이 있는 것같은데 문제 없나요?
0
79
2
@PrePersist, @PreUpdate 호출 시점 질문드립니다.
0
104
2
Sort 인터페이스는 잘 사용 안하나요?
0
61
1
스캔대상 질문드립니다.
0
50
1
하이버네이트6에서의 최적화에 이은 질문
0
92
1
save() vs saveAndFlush DB 통신 횟수
0
61
1
순수 JPA 리포지토리 코드 수정부분
0
93
2
bulk연산 후 flush하는 이유를 모르겠어요
0
164
3
bulk insert 질문입니다.
0
191
2
교만했던 것 같아요.
0
152
1
RESTful 강의는 안하시는 건지 궁금합니다.
0
154
2
동적 테이블에 대한 질문
0
90
1
영속성 전이와 연관관계
0
142
2
강의 10:25 질문
0
80
1
단건 update 질문
0
104
2
엔티티 와 도메인의 경계
0
132
1
UsernameOnlyDto 타입 type mismatch 오류
0
123
1





