일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 산업은행청년인턴
- springboot
- 운영체제
- 산업은행it
- 2178
- CS
- Spring JPA
- 스케일아웃
- 트리맵
- BFS
- 그래프탐색
- 프로그래머스
- 코테
- 프로젝트
- 컴퓨터구조
- fatch
- 트리셋
- SpringBatch
- findById
- CPU스케줄링
- 파이널프로젝트
- 폰켓몬
- 백준
- 해시
- DB replication
- JPA
- 임베디드타입
- 외래키제약조건위반
- flyway
- 구현
- Today
- Total
나 JAVA 봐라
[Spring JPA] Spring JPA 와 SQL의 연관관계 본문
현재 프로젝트에서 Flyway로 데이터베이스 스키마 생성, 변경을 하고 이 후 CRUD 작업은 Spring JPA로 하고 있다.
그러던 중 각 방식에서 연관관계를 맺는 방식에 차이가 있는 것을 보고 정리해본다.
Spring JPA 란?
Spring JPA(Java Persistence API)는 자바 ORM(Object-Relational Mapping) 표준으로, 객체와 데이터베이스 테이블 간의 매핑을 쉽게 처리할 수 있게 도와준다. 스프링 JPA는 기본적으로 JPA를 사용하면서 스프링에서 제공하는 추가적인 기능을 사용할 수 있게 한다.
Spring JPA 주요 특징
- 개발 편의성 향상 : Spring JPA는 개발자가 직접 SQL 쿼리를 작성하는 대신, 메소드 이름만으로 데이터베이스의 CRUD 연산을 수행할 수 있는 기능을 제공한다. 예를 들어, findByName(String name)과 같은 메소드를 작성하면, Spring JPA가 이를 해석하여 적절한 SQL 쿼리를 생성하고 실행한다.
- 데이터 접근 추상화, 자동화: Spring JPA는 DB 엔진에 대한 종속성을 줄이고, 데이터 접근 계층을 '객체 지향' 적으로 다루게 도와준다. 이는 다양한 DB 엔진에 대한 코드 변경을 최소화하고, 개발자가 비즈니스 로직에 더 집중할 수 있게 한다.
- 성능 최적화 기능: Spring JPA는 JPA가 제공하는 다양한 성능 최적화 기능(1차 캐시, 지연 로딩, 쓰기 지연) 등을 사용할 수 있다.
- 트랜잭션 관리 : 스프링 프레임워크의 @Transactional 어노테이션을 이용하여 선언적인 트랜잭션 관리를 지원한다. 이를 통해 트랜잭션의 시작, 커밋, 롤백 등을 개발자가 직접 관리하지 않아도 된다.
따라서, Spring JPA를 사용하여 더 쉽고 효율적으로 개발할 수 있게 된다.
Flyway 란?
데이터베이스 마이그레이션을 도와주는 오픈 소스 도구이다. Flyway는 버전 관리 시스템과 비슷한 방식으로 데이터베이스 스키마의 버전을 관리한다.
** 데이터베이스 마이그레이션 : 데이터베이스의 스키마 버전을 관리하고 변경하는 과정
Flyway 주요 특징
- 버전 관리: Flyway는 각 마이그레이션 스크립트에 버전 번호를 부여한다. 이를 통해 어떤 버전이 적용되었는지, 어떤 버전이 적용되어야 하는지를 명확하게 관리할 수 있다.
- 마이그레이션 스크립트 실행: Flyway는 SQL 스크립트를 실행하여 데이터베이스 스키마를 변경한다. 이 스크립트는 데이터베이스 테이블 생성, 입력, 구조 변경 등의 작업을 수행한다.
- 초기화 및 복구: Flyway는 데이터베이스를 특정 버전으로 초기화하거나, 이전 상태로 복구하는 기능을 제공한다.
- 플랫폼 독립성: Flyway는 다양한 데이터베이스 시스템을 지원한다. 따라서 데이터베이스 종류에 상관없이 일관된 방식으로 데이터베이스 마이그레이션을 관리할 수 있다.
따라서 Flyway를 사용하면, 데이터베이스 스키마 변경을 안전하고 효율적으로 관리할 수 있다. 이런 점을 특히 팀에서 함께 작업하거나, 프로덕션 환경에서 데이터베이스 변경을 관리해야 할 때 유용하다.
Flyway와 Spring JPA 함께 사용하기
Spring JPA만 사용하기
Spring JPA는 spring.jpa.hibernate.ddl-auto 설정에 따라 데이터베이스 스키마를 자동으로 생성하거나 업데이트한다. 예를 들어 이 값을 create로 설정하면, 애플리케이션 시작 시점에 JPA가 데이터베이스 스키마를 생성한다.
그러나 이 방식은 개발 과정에서 편리하긴 하지만, 데이터베이스 마이그레이션을 정밀하게 제어하기 어렵다는 단점이 있다. 또한, 실제 운영 환경에서는 이런 방식으로 데이터베이스 스키마를 자동으로 변경하는 것은 위험할 수 있다.
Spring JPA + Flyway 사용하기
Flyway와 같은 데이터베이스 마이그레이션 도구를 사용하면, 데이터베이스 스키마 변경을 좀 더 안전하고 통제된 방식으로 관리할 수 있다. Flyway는 버전 관리된 SQL 스크립트를 순차적으로 실행하여 데이터베이스 스키마를 변경하기 때문이다.
즉, Spring JPA와 Flyway를 함께 사용하는 경우, 일반적으로는 Flyway가 데이터베이스 스키마의 생성과 변경을 담당하고, Spring JPA는 이후의 데이터베이스 작업 CRUD를 담당한다. 이렇게 하면 데이터베이스 스키마 변경을 안전하게 관리하면서, 동시에 객체지향적인 데이터베이스 작업을 수행할 수 있다.
추가로 둘을 같이 사용하려면 엔티티의 필드마다 @Column 어노테이션을 추가로 붙여줘야 한다.
JPA만 사용했을 때는 데이터베이스 스키마를 JPA가 생성했기 때문에 상관 없지만, 둘을 함께 사용했을 때에는 데이터베이스 스키마는 Flyway, 이 후 데이터베이스 작업은 JPA가 하기 때문에, 생성된 데이터베이스의 테이블, 필드들과 엔티티가 동일한 것이라는 표시를 해주어야 JPA가 인식할 수 있다.
Flyway와 Spring JPA의 연관관계
- SQL : Flyway의 스크립트는 SQL로 작성된다. SQL에서는 테이블 간의 연관 관계를 표현하기 위해 외래 키(Foreign Key)를 사용한다. 외래 키는 한 테이블의 필드가 다른 테이블의 기본 키(Primary Key)를 참조함으로써 두 테이블 사이의 연관 관계를 정의한다.
- JPA : JPA에서는 객체 간의 연관 관계를 표현하기 위해 @ManyToOne, @OneToMany, @OneToOne, @ManyToMany 등의 어노테이션을 사용한다.
현재 하고 있는 프로젝트에서 각자 다른 방식으로 연관관계를 표현한 엔티티를 예로 들면,
- Review, User 를 참조하는 ReviewReaction 엔티티 -> SQL 작성할 때 FK로 연관관계를 표현했다.
- Gym, User 를 참조하는 Review 엔티티 -> JPA의 @ManyToOne을 사용하여 연관관계를 표현했다.
위의 두 엔티티는 다른 방식으로 연관관계를 표현했고, 모두 User 를 참조하고 있다.
앞으로 참조되고 있는 User를 부모, 참조하고 있는 Review와 ReivewReaction 을 자식엔티티라고 표현해볼 것이다.
만약, 참조하고 있는 부모 엔티티가 삭제된다면 자식 엔티티는 어떻게 될까?
기존의 데이터베이스에는, User 테이블에 id가 1인 엔티티가 있다.
review 테이블에는 user_id가 1인 엔티티를 참조하는 review 엔티티가 2개 존재한다.(JPA로 연관관계 매핑)
review_reaction 테이블에는 user_id가 1인 엔티티를 참조하는 review_reaction 엔티티가 2개 존재한다. (SQL로 연관 매핑)
이런 상황에서 user_id가 1인 부모 엔티티를 삭제하고 난 후, 각 자식 테이블을 살펴본다.
먼저 JPA로 연관관계를 맺어준 review table을 보면, 부모 엔티티가 사라지더라도, 리뷰가 그대로 남아있다.
다음으로는 FK로 연관관계를 맺어준 review_reaction 테이블이다.
부모 엔티티가 사라짐에 따라, 해당 엔티티를 참조하는 자식 엔티티도 삭제되었다.
그런데 이 상태에서 JPA로 연관관계를 맺어준 리뷰 테이블을 조회하면 어떻게 될까?
여전히 데이터 베이스에는 리뷰가 남아있음에도, 리뷰는 없다고 조회가 된다.
그러면 FK를 사용하지 않고, JPA로만 부모 엔티티 삭제 시 자식 엔티티까지 함께 삭제하게 하는 방법이 있을까?
먼저는 부모 엔티티에도 @OneToMany 연관관계를 만들어주고, 함께 삭제될 수 있도록 CascadeType.REMOVE 옵션을 줄 수 있다.
하지만, 현재 프로젝트의 설계에서는 부모 엔티티가 자식 엔티티를 필드 값으로 가지고 있지 않다. 이런 경우에는 해당 옵션을 사용할 수 없고, 대신 서비스 레이어의 부모 엔티티가 삭제되는 메소드에서, 자식 엔티티까지 함께 삭제될 수 있도록 해야한다.
( + 문득 생각이 들었는데, Entity Listener 를 통해 처리해도 좋을 것 같다)
그런 이유로, 이번 프로젝트에서는 부모 엔티티 삭제 시 자식 엔티티까지 삭제해야하는 경우, SQL을 사용하여 FK를 맺어줌으로써 별다른 코드 작성 없이도 데이터베이스 레벨에서 제약조건을 관리할 수 있도록 했다.
만약, 프로젝트에서 Flyway를 통해 버전 관리도 함께 하고 있다면, 정책에 따라서 적절한 방법으로 연관관계를 표현하여 수고를 덜면 좋을 것 같다.
'Spring > Spring JPA' 카테고리의 다른 글
@Transactional과 DataIntegrityViolationException (1) | 2024.01.10 |
---|---|
[Spring JPA] JPA의 findById와 EAGER, LAZY 전략 (0) | 2024.01.04 |