반응형

일반적으로 REST API를 만들게 되면 @RestController를 이용하여 JSON 형식으로 값을 반환하게 됩니다. 일반적으로 데이터를 반환할 때 상태값을 넘겨주는데 이 때 사용하는 게 Spring Framework에서 제공하는 ResponseEntity입니다.

 

ResponseEntity는 HttpEntity를 상속받습니다.

ResponseEntity의 HttpEntity 상속

위 이미지처럼 ResponseEntity는 HTTP 요청에 의한 HttpStatus, HttpHeader와 HttpBody를 포함하는 HttpEntity 클래스를 상속받습니다.

 

반응형
반응형

우선, JPA의 관계 매핑을 알아보기 전에 객체의 연관 관계와 테이블의 연관 관계의 차이를 알아봅시다.

 

테이블 : 외래키로 조인하여 연관된 테이블을 찾습니다.

객체 : 객체를 참조하여 연관된 객체를 찾습니다.

 

테이블은 조인을 통해 양방향 연관 관계 설정이 가능하지만 객체에는 양방향 연관 관계 설정이 없으므로 다른 두 객체에 각각 단방향 연관 관계를 설정해야 합니다.

 

게시판 예제를 통해 확인해봅시다.

 

Article

@Entity
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    
    private String content;

    ...
}

Member

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String memberId;

    private String memberPass;
    
    ...
}

 

게시판 객체와 회원 객체가 있을 때 게시판 객체에서는 회원 정보를 얻고 반대로 회원 객체에서는 회원이 작성한 모든 글을 가지고 오고 싶습니다.

 

@ManyToOne과 OneToMany

두 객체를 연결하기 위해 Article 객체 필드에 Member 객체를 만들었고, Member 객체 필드에는 List 타입의 Articles라는 필드를 만든 후 각각 @ManyToOne과 @OneToMany를 붙여줬습니다.

 

@ManyToOne : 다대일, 한 명의 회원이 여러 게시글을 작성할 수 있으므로 게시글(Article) 기준으로 @ManyToOne을 선언합니다.

@OneToMany : 일대다, 회원 한 명이 게시글을 여러 개 작성할 수 있으므로 회원(Member) 기준으로 @OneToMany를 선언합니다.

 

@Entity
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    
    private String content;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;

    ...
}


@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String memberId;

    private String memberPass;
    
    @OneToMany(mappedby = "member")
    private List<Article> articles = new ArrayList<Article>();
    
    ...
}

 

@ManyToOne(fetch = FetchType.LAZY) : fetch로 로딩 전략을 설정합니다. FetchType.LAZY는 지연 로딩을 의미합니다.

@OneToMany(mappedby = "member") : 일대다 관계를 연결할 상대 객체의 @JoinColumn이 선언된 필드값을 적습니다.

 

mappedby란?

JPA로 연관 관계를 설정할 때 가장 혼동하기 쉬운 부분인데 mappedby는 연관 관계 객체의 반대 객체에 선언합니다.

 

연관 관계 주인 : 외래키가 있는 객체

* 예시에서는 외래키가 Article에 있으므로 Article이 연관 관계의 주인

 

즉, 위 예시에서는 Article과 Member 중에서 Article이 외래키 member_id 라는 컬럼에 해당하는 member를 갖고 있으므로 Article이 연관 관계의 주인입니다.

 

따라서 연관 관계 주인 Article과 연관 관계로 설정된 Member 객체의 articles 필드 위 @OneToMany 안에 (mappedby를 넣고 연관 관계 주인 객체의 연결 필드명 "member"를 넣어주시면 됩니다.

 

처음 해보시면 되게 혼란스러우실 수 있는데 우리나라 JPA 최고 권위자이신 김영한 선생님의 강의 영상 첨부하니 확인해보세요!

 

반응형

'Java Web > JPA' 카테고리의 다른 글

[JPA] persistence.xml 작성 예시  (0) 2022.03.02
[JPA] 연관 관계 편의 메소드  (0) 2022.02.28
[JPA] Auditing 정리  (0) 2022.02.14
[JPA] findAll 정렬  (0) 2021.07.23
[JPA] JPA란?  (0) 2021.05.13
반응형

JPA Auditing

Java 표준 ORM 기술 JPA를 사용할 때 데이터 생성일자, 수정일자 등 어떤 테이블이든 공통으로 갖고 있는 컬럼을 관리하기 위해 제공하는 기능입니다. 이 기능을 사용하면 테이블과 매핑하여 데이터 입력 시 자동으로 시간을 관리할 수 있습니다.

 

BaseTimeEntity 생성

@Getter
@MappedSuperClass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
    
    @CreatedDate
    private LocalDateTime createdDate;
    
    @LastModifiedDate
    private LocalDateTime updatedDate;

}

 

@MappedSuperClass : JPA에서 관리하는 Entity 클래스가 해당 추상 클래스를 상속하면 createdDate와 updateDate를 컬럼으로 인식하게 해 줍니다.

 

@EntityListeners(AuditingEntityListener.class) : 해당 클래스가 Auditing 기능을 포함하게 됩니다.

 

@CreatedDate : 데이터가 입력될 때 자동으로 시간을 저장해줍니다.

 

@LastModifiedDate : 데이터의 값이 변경될 때 자동으로 시간을 저장해줍니다.

 

Article

@Getter
@NoArgsConstructor
@Entity
public class Member extends BaseTimeEntity {

    ... 내용 생략

}

 

위처럼 @Enitity로 지정된 클래스가 BaseTimeEntity를 상속받으면 사용 가능합니다. 

 

BoardApplication

@EnableJpaAudithing
@SpringBootApplication
public class BoardApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
}

 

마지막으로 해당 프로젝트의 Application 클래스에 @EnableJpaAuditing 어노테이션을 추가함으로써 어플리케이션 내에서 Auditing 기능을 활성화할 수 있습니다.

 

UserRepositoryTest

@SpringBootTest
public class MemberRepositoryTest {

    @Autowired
    private UserRepository UserRepository;

    @Test
    public void insert() {
        String userId = "test01";

        // 실행 시간보다 전으로 임의 시간 지정
        LocalDateTime currentTime = LocalDateTime.of(2022, 2, 14, 0, 0, 0);

        User user = User.builder()
                .userId(userId)
                .userPass("test01")
                .userName("test01")
                .userEmail("test01@gmail.com")
                .build();

        userRepository.save(user);

        // 11행에서 선언한 currentTime보다 테이블에서 새로 입력된 값의 시간이 뒤인지 확인
        assertThat(userRepository.findAll().get(0).getCreatedDate()).isAfter(currentTime);

    }
}

 

Test 클래스를 하나 만들어서 board 테이블에 실행한 시간을 잘 저장했는지 테스트해봅니다.

 

MySQL Workbench에서 확인한 결과 작성일자와 수정일자이 현재 시간으로 저장된 것을 볼 수 있습니다.

반응형

'Java Web > JPA' 카테고리의 다른 글

[JPA] persistence.xml 작성 예시  (0) 2022.03.02
[JPA] 연관 관계 편의 메소드  (0) 2022.02.28
[JPA] 양방향 관계 매핑 @OneToMany, @ManyToOne 그리고 mappedby  (1) 2022.02.16
[JPA] findAll 정렬  (0) 2021.07.23
[JPA] JPA란?  (0) 2021.05.13
반응형

인덱스(Index)

데이터베이스에서 Index라는 개체는 테이블의 검색 능력을 향상시키는 데에 중요한 역할을 합니다. 인덱스는 어떻게 생성하는 거고 왜 사용해야 할까요?

 

검색 능력 향상

인덱스를 사용하지 않고 검색하면 조건에 맞는 데이터를 찾기 위해 테이블에 있는 데이터를 모두 조회합니다. MySQL에서 제공하는 샘플 데이터 employees에서 데이터를 조회하여 확인해봅시다.

 

explain select * from employees where first_name = 'Georgi';

 

샘플 데이터를 가지고 위 쿼리를 실행했습니다.

 

결과를 보면 네번째 컬럼 type에 ALL이 들어간 걸 볼 수 있습니다. 또 row 컬럼의 값이 299778인데 이는 해당 데이터를 조회하기 위해 순회한 열의 갯수입니다. 즉, 인덱스를 사용하지 않고 검색을 했을 때는 테이블에 있는 모든 데이터를 순회하기 때문에 속도가 느려집니다. 그러면 인덱스를 사용하면 어떻게 될까요?

 

인덱스 생성

create index idx_employees_first_name on employees(first_name);

 

위 쿼리는 테이블 'employees'의 컬럼 'first_name'에 인덱스를 생성하는 쿼리입니다. create index 뒤에 'idx_employees_first_name'에서 idx는 index를 의미하고 그 뒷부분은 테이블 이름과 컬럼 이름입니다. 이렇게 생성하고 앞에서 검색했던 내용을 다시 검색해보겠습니다.

 

아까는 type에 ALL이라고 적혀있었으나 ref(참조)로 바뀐 것을 볼 수 있고 rows도 253으로 줄어든 것을 볼 수 있습니다. 기존에 모든 데이터를 순회하여 찾는 방식과 다르게 인덱스를 이용하면 해당 데이터가 어디 있는지 알고 있기 때문에 검색 속도가 줄어들게 되고 데이터가 많을 때 검색 속도를 향상시킬 수 있는 데이터베이스 튜닝은 한 가지 방법입니다.

반응형

+ Recent posts