작성
·
415
0
안녕하세요 선생님 스프링부트를 이용한 프로젝트를 진행중에 궁금한 것이 생겨서 꼭 알고 싶은 마음에 질문하게 되었습니다.
프로젝트 구성은 이렇습니다. 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를 조회하시면 될꺼에요.
감사합니다.