Transactional 과 Lazy Loading
176
작성한 질문수 4
안녕하세요 강의 잘 듣고 있습니다.
다름이 아니라 프로젝트를 업그레이드 하는 과정에서 오류가 생겨 질문 드립니다.
package ShopProject.myShopProject.Domain;
import ShopProject.myShopProject.Domain.Item.Item;
import ShopProject.myShopProject.Domain.Order.Order;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Entity
@Getter @Setter
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String name;
@Embedded
private Address address;
@OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE)
private List<Order> orders = new ArrayList<>();
private String loginId;
private String password;
@OneToMany(mappedBy = "member")
private List<LikedItem> likedItems = new ArrayList<>();
}
package ShopProject.myShopProject.Domain;
import ShopProject.myShopProject.Domain.Item.Item;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter
@Setter
public class LikedItem {
@Id
@GeneratedValue
@Column(name = "likedItem_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;
}
보시는 것처럼 멤버와 좋아요 상품은 Lazy 관계에 있습니다.
OneToMany는 기본이 Lazy이므로 명시하지 않았습니다.
따라서 좋아요 상품은 직접 조회될 때만 DB에서 조회되고, 다른 경우는 프록시 형태로 존재합니다.
//아이템 상세 정보
@GetMapping("item")
public String itemDetail(@RequestParam("itemId") Long itemId,
@SessionAttribute(name = "loginMember") Member loginMember,
Model model) {
log.info("item 호출");
Item item = itemService.findOne(itemId);
log.info(loginMember.getLoginId() + " " + loginMember.getName());
// 좋아요 여부 추가
model.addAttribute("isLiked", memberService.isliked(loginMember, item)); //이 부분입니다!!
model.addAttribute("item", item);
model.addAttribute("member", loginMember);
if (item.getCategory().equals("Book")) {
return "items/item/book";
}
if (item.getCategory().equals("Album")) {
return "items/item/album";
}
if (item.getCategory().equals("Movie")) {
return "items/item/movie";
}
return "items/item";
}
위 컨트롤러를 호출하면, isliked라는 매소드를 실행하게 됩니다. 좋아요 여부를 확인하는 메소드입니다.
//좋아요 아이템이 아니면 false 반환
@Transactional
public Boolean isliked(Member member, Item item) {
log.info("좋아요 확인 메서드 실행");
//
log.info("멤버 정보" + member.getName() + " " + member.getLoginId());
for (LikedItem likeditem: member.getLikedItems()) {
//여기에서 lazyinitializationError 발생
if (likeditem.getItem().getName().equals(item.getName())) {
log.info("좋아요인 경우");
return true;
}
}
log.info("좋아요 아닌 경우");
return false;
}
그런데 여기에서 맴버의 좋아요 목록을 불러오면 lazyinitialization 에러가 발생합니다...
정말 많이 원인도 구글링해보았는데, 영속성 컨텍스트가 종료 된 후 접근할 때 발생하는 것을 알았습니다.
영속성 컨텍스트의 생명주기는 트렌잭션과 거의 동일하다고 알고 있습니다.
만약 위 메소드에 트렌젝션 어노테이션이 없다면 member.getLikedItems() 의 결과를 초기화해주지 않으면 오류가 발생할 것입니다.
따라서 트렌젝션 어노테이션을 넣으므로서, member.getLikedItems()를 가져오고, 직접 DB에서 불러오는 과정을 한 트랜젝션 안에서 수행하도록 했습니다.
그런데 이 메서드에서 계속 LazyinitializatoinError가 발생합니다. 이 부분의 원인을 전혀 못 찾겠습니다..
해결책으로는 DTO를 사용하거나, fetch Join을 사용해서 멤버와 같이 조인하여 한번에 가져옴으로 해결할 수있을 거라 생각합니다.
하지만 해결책은 알았지만, 위 코드의 무슨 오류가 있는지 정말 궁금합니다.
따라서 이 코드의 오류를 알고 싶습니다. 또한 저의 이해에 오류가 있다면 그 부분도 알려주시면 감사하겠습니다.
답변 1
0
안녕하세요. ml505050님, 공식 서포터즈 y2gcoder입니다.
예외 트레이스를 전부 올려주시거나 코드를 올려주시면 더 정확한 답변이 될 것이라 생각하나, 일단 올려주신 코드와 상황만을 봤을 때는 member를 준영속 상태로 서비스단으로 넘겨주기 때문이라고 생각합니다.
서비스단에서 member의 id로 member를 다시 조회해옴으로써 영속화된 member를 찾아오셔서 다시 시도해보시거나,
아니면 세션에 로그인된 멤버 객체를 저장할 때 fetch join이든, 프록시 초기화를 사용하시든 하여 likedItems를 미리 초기화한 후 저장하시거나,
혹은(이건 다른 얘기일 수도 있으나 영한님도 권장하는 방법입니다) DTO를 만들어 필요한 정보만 넣어 세션에 저장 후 불러오시는 것을 추천합니다.
감사합니다.
벌크연산에서 member.getAge 호출 시 영속성 컨텍스트에서 데이터를 가져오는건가요?
0
38
2
inheritance startegy 선택시 고려사항
0
26
1
Entity 동등성 비교
0
27
1
실무 조언 관련 질문입니다.
0
52
1
H2데이터베이스 파일 생성
0
61
2
서브쿼리 강의에서 ALL 예시 관련 질문드립니다.
0
58
2
수정또는 삭제시 영속성 엔티티에 값이 무조건 있어야 하나요?
0
58
1
JPQL 메소드와 락
0
57
1
Delivery @OneToOne
0
64
1
17강 4~5분대 테이블 값 조회가 안됩니다.
0
98
2
UnsupportedOperationException 발생
0
89
3
H2 Database 연결이 안됩니다.
0
98
2
연관관계 매핑 질문드립니다.
0
88
2
h2데이터베이스 실행오류
0
110
2
persistence.xml
0
113
2
양방향 연관관계에서 연관관계의 주인(mappedBy)을 왜 꼭 정해야 하나요?
0
84
1
영속성 컨텍스트
0
70
1
JPA 프록시
0
100
1
Native Query와 MyBatis
0
74
1
영속성 컨텍스트는 어떤 메모리에 저장되는건가요?
0
94
1
임베디드 타입 예시 코드 관련 질문
0
121
3
명시적 조인에서 별칭을 주면 왜 객체에 접근할 수 있나요
0
97
3
인텔리제이 패키지 커서 단축키 질문
0
109
2
혹시 현재는 ID 데이터 타입이 String이면 안되나요?
0
149
1





