cmm_file, member -> 1 : 1 관계
member, message -> 1 : N 관계
member, message_request -> 1 : N 관계
member, friend_relation -> 1 : N 관계
Mybatis로 구현되어 있을 때는 RDB 그대로 복합키 만듦
JPA로 리팩토링 할 때는 대리키를 만들어 각각의 엔티티를 정의하고 관계를 매핑함
PK로 매핑하지 않았을 경우 나타난 문제점
@Entity
public class UploadFile {
@Id @GeneratedValue
@Column(name = "file_id")
private Long id;
private String targetId;
private String localFileName;
private String filePath;
private String realFileName;
public UploadFile(String realFileName, String localFileName, String filePath) {
this.realFileName = realFileName;
this.localFileName = localFileName;
this.filePath = filePath;
}
public void setTargetId(String targetId){
this.targetId = targetId;
}
}
@Entity
public class Member implements Serializable {
@Id
private String memberId;
private String id;
private String password;
private String nickname;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "file_id")
private UploadFile uploadFile;
public Member(String id, String password) {
this.id = id;
this.password = password;
}
public Member(String memberId, String id, String nickname, String password) {
this.memberId = memberId;
this.id = id;
this.nickname = nickname;
this.password = password;
}
public void setUploadFile(UploadFile uploadFile) {
this.uploadFile = uploadFile;
}
public void setId(String id){
this.id = id;
}
}
@Entity
public class FriendRelation implements Serializable {
@Id @GeneratedValue
Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "my_id", referencedColumnName = "id")
private Member me;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="friend_Id", referencedColumnName = "id")
private Member friend;
private String status;
public FriendRelation(Member me, Member friend, String status) {
this.me = me;
this.friend = friend;
this.status = status;
}
}
@Entity
public class Message {
@Id @GeneratedValue
@Column(name = "message_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "sender_id", referencedColumnName = "id")
private Member sender;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "receiver_id", referencedColumnName = "id")
private Member receiver;
private LocalDateTime regDate;
private String body;
private String title;
public Message(Member sender, Member receiver, SendMessageRequest messageRequest) {
this.sender = sender;
this.receiver = receiver;
this.title = messageRequest.getTitle();
this.body = messageRequest.getBody();
}
}
@Entity
public class MessageRequest {
@Id @GeneratedValue
@Column(name = "message_request_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "my_id", referencedColumnName = "id")
private Member me;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "friend_id", referencedColumnName = "id")
private Member friend;
private String status;
private LocalDateTime requestDate;
public MessageRequest(Member me, Member friend, String status) {
this.me = me;
this.friend = friend;
this.status = status;
}
}
내 소스 상에서 N+1이 나탈 날 수 있는 지점은 다음과 같다
매핑된 정보의 fetch를 FetchType.LAZY로 우선 다 설정하였고
멤버 정보가 필요한 곳은 join fetch을 사용하여 해결하였음
public List<Message> findAllReceivedList(String myId, int offset, int limit) {
return em.createQuery(
"select ms " +
"from Message ms " +
"join fetch ms.sender " +
"join fetch ms.receiver " +
"where ms.receiver.id = :myId", Message.class)
.setParameter("myId", myId)
.setFirstResult(offset)
.setMaxResults(limit)
.getResultList();
}
Repository 테스트 코드 작성
Service 테스트 코드 작성
Controller 테스트 코드 작성
/**
* 보낸 메시지 목록
* @param offset
* @param limit
* @param request
* @return
*/
@GetMapping
@RequestMapping("sent-list")
public Result sentList(@RequestParam(defaultValue = "1") int offset,
@RequestParam(defaultValue = "100") int limit, HttpServletRequest request) {
String myId = (String)request.getSession().getAttribute(SessionConst.ID);
Result result = new Result();
try{
List<MessageDto>messageDtos = messageService.findAllSentList(myId, offset, limit);
result.setData(messageDtos);
result.setResultCode(CustomRespond.FAIL.getShortStatus());
return result;
} catch (Exception e){
result.setResultCode(CustomRespond.FAIL.getShortStatus());
return result;
}
}
@Data
public class Result<T> {
private T data;
private String resultCode;
}