일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- gradle
- sql
- 반복문
- 2차원배열
- 프로그래머스
- 시큐리티
- 소스트리
- 시큐리티로그인
- 시큐리티 로그인
- 로그인
- java
- codingtest
- 목록
- 시큐리티 로그아웃
- Linux
- html
- input태그
- programmers
- security
- Spring boot
- 스프링 부트
- 싱글톤
- JAVA11
- javascript
- StyleSheet
- css
- springboot
- 리눅스
- springSecurity
- 코딩테스트
Archives
- Today
- Total
JAVAIARY
N:1(다대일) 연관관계 1 본문
연관관계와 관계형 데이터베이스 설계
- 관계형 데이터베이스 - 개체(entity)간의 관계(relation)를 통해 구성
- ex) 회원과 게시글의 관계
- 1명의 회원은 여러(N)개의 게시글을 작성할 수 있음
- 1개의 게시글은 1명의 회원에 의해서 작성됨
- 하나의 ID(기본키)가 여러 게시글에서 참조되도록 설계
1. 엔티티 생성
1-2. Member 엔티티 생성
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public class Member extends BaseEntity{
@Id
private String email;
private String password;
private String name;
}
- 회원 엔티티는 PK만을 가지고 있으므로 별도의 FK 필요 없음
1-2. Board 엔티티 생성
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public class Board extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long bno;
private String title;
private String content;
//작성자 처리는 추후에 추가
}
1-3. Reply 엔티티 생성
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public class Reply extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long rno;
private String text;
private String replyer;
//Board와의 연관관계 추후 작성
}
2. @ManyToOne 어노테이션
- FK(외래키)를 이용한 참조를 위한 어노테이션
2-1. Board에 작성자(writer) FK 추가
2-2. Reply 에 게시판(board) FK 추가
3. Repository 생성
public interface MemberRepository extends JpaRepository<Member, String> {
}
public interface BoardRepository extends JpaRepository<Board, Long> {
}
public interface ReplyRepository extends JpaRepository<Reply, Long> {
}
4. 연관관계 InsertTest
4-1. RepoitoryTests 생성
4-2. MemberRepositoryTests
@SpringBootTest
public class MemberRepositoryTests {
@Autowired
private MemberRepository memberRepository;
@Test
public void insertMembers(){
IntStream.rangeClosed(1,100).forEach(i -> {
Member member = Member.builder()
.email("user"+i+"@aaa.com")
.password("1111")
.name("user"+i)
.build();
memberRepository.save(member);
});
}
}
4-3. BoardRepositoryTests
@SpringBootTest
public class BoardRepostoryTests {
@Autowired
private BoardRepository boardRepository;
@Test
public void insertBoard() {
IntStream.rangeClosed(1, 100).forEach(i -> {
Member member = Member.builder().email("user" + i + "@aaa.com").build();
Board board = Board.builder()
.title("Title..." + i)
.content("Content...." + i)
.writer(member).
build();
boardRepository.save(board);
});
}
}
4-4. ReplyRepositoryTests
@SpringBootTest
public class ReplyRepositoryTests {
@Autowired
private ReplyRepository replyRepository;
@Test
public void insertReply() {
IntStream.rangeClosed(1, 300).forEach(i -> {
// 1부터 100까지의 임의의 번호
long bno = (long) (Math.random() * 100) + 1;
String email = "user" + bno + "@naver.com";
Board board = Board.builder().bno(bno).build();
Reply reply = Reply.builder()
.text("Reply Text..." + i)
.board(board)
.replyer(email)
.build();
replyRepository.save(reply);
});
}
}
5. Join 처리 Test
5-1. BoardRepositoryTests
@Test //select
public void testRead1(){
Optional<Board> result = boardRepository.findById(100L);
Board board = result.get();
System.out.println(board);
System.out.println(board.getWriter());
}
- @ManyToOne 으로 엮인 엔티티들이 자동으로 조인처리되어 함께 가져옴
5-2. ReplyRepositoryTests
@Test
public void readReply1(){
Optional<Reply> result = replyRepository.findById(1L);
Reply reply = result.get();
System.out.println(reply);
System.out.println(reply.getBoard());
}
6. fetch를 통한 Lazyloading(지연로딩) 처리 - 권장됨
- fetch : JPA에서 연관관계의 데이터를 어떻게 가져올 것인가
어노테이션 속성으로 fetch모드 지정 - Eager Loading: 즉시 로딩
특정 엔티티를 조회할 때 연관관계를 가진 모든 엔티티를 같이 로딩
연관관계가 복잡할수록 조인으로 인한 성능저하 초래 - Lazy Loading: 지연 로딩
장점: 조인을 하지 않기 때문에 하나의 테이블을 이용하는 경우에는 빠른 처리 가능
단점: 필요한 순간에 쿼리를 실행해야 하기 떄문에 연관관계가 복잡한 경우, 여러번의 쿼리가 실행
7. JPQL 사용하기
- JPQL
- 테이블이 아닌 엔티티 객체를 대상으로 검색하는 객체지향 쿼리
- SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않음
= JPQL 문법만 알면 여러 데이터베이스를 쉽게 다룰 수 있게 됨 - JpaRepository(인터페이스)에서 JPQL을 분석하여 데이터베이스를 조회
= 자동 번역 - 방언(Dialect)만 변경하면 JPQL을 수정하지 않고 자연스럽게 DB 변경 가능
1) 엔티티 클래스 내부에 연관관계가 있는 경우
@ManyToOne(fetch = FetchType.LAZY) // 명시적으로 Lazy 로딩 지정
- @ManyToOne어노테이션을 사용하는 경우 지연로딩 명시적 표시
@Query("select b, w from Board b left join b.writer w where b.bno =:bno")
Object getBoardWithWriter(@Param("bno") Long bno);

- testRead1() 테스트를 실행시키면 오류발생
- @Transactional 어노테이션 추가
- 정상적으로 Board조회 후, Member 조회
연관관계에서는 @ToString() 주의
exclude의 속성값으로 지정된 변수는 toString()에서 제외하기 때문에 지연 로딩을 할 때는 반드시 지정해 주는 것이 좋음.
2) 연관관계가 없는 엔티티 조인 처리 = on 사용
@Query("SELECT b, r FROM Board b LEFT JOIN Reply r ON r.board = b WHERE b.bno = :bno")
List<Object[]> getBoardWithReply(@Param("bno") Long bno);
- reply 내의 board는 참조를 하고 있으나, board는 reply를 참조하고 있지 않으므로 on 을 통해
r.board = b.bno 를 명시해줌
@Test
public void testGetBoardWithReply(){
List<Object[]> result = boardRepository.getBoardWithReply(100L);
for(Object[] arr : result){
System.out.println(Arrays.toString(arr));
}
}
'Project > 2023.02~ ) Study toy 프로젝트' 카테고리의 다른 글
프로젝트 적용하기(Board) (0) | 2023.03.06 |
---|---|
N:1(다대일) 연관 관계 2 - JPQL과 LEFT(OUTER) JOIN (0) | 2023.03.05 |
검색 처리 (0) | 2023.02.27 |
Spring Boot) 게시글 수정/ 삭제 처리 (0) | 2023.02.21 |
Spring Boot) 게시글 등록 페이지 / 등록 처리 (0) | 2023.02.20 |