728x90
개요
조직-부서 관계를 가진 Entity를 개발 중에 발생한 문제였습니다.
조직은 여러 개의 부서를 가질 수 있는 다대 다 관계의 모델을 구성했는데, 조직이 삭제되면 하위에 있는 모든 부서가 삭제되어야 하는 기능입니다.
1 2 3 4 | @OneToMany(mappedBy = "organization", cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER) @OnDelete(action = OnDeleteAction.CASCADE) @JsonBackReference private List<Department> departments = new ArrayList<>(); | cs |
위와 같이 구현을 완료하고 삭제 버튼을 클릭하는 순간 DataIntegrityViolationException이 떨어지는군요.
분명 API에서 하라는 대로 했는데.. 이게 무슨 말도안돼는..?
그래서 작성한 가이드입니다.
개발 환경
Spring Boot 1.5.19.RELEASE
Mariadb 10.1.36
해결 방법
본 포스트에서는 예제보다 결론을 먼저 보여드리는 것이 좋은 방법일 것 같아 해결책을 먼저 제시합니다.
결론적으로는 Database Dialect를 잘못 사용하였습니다.
제가 구축하는 시스템에서는 Mariadb의 InnoDB를 사용하고 있는 데, 설정은 MySQLDialect로 되어 있더군요.
이게 무슨 말이냐 하면, 해당 클래스를 들여다 보면 쉽게 이해 할 수 있게 됩니다.
아래는 MySQLDialect.java의 supportsCascadeDelete() 메소드 입니다.
1 2 3 4 | @Override public boolean supportsCascadeDelete() { return false; } | cs |
아래는 MySQLInnoDBDialect.java의 supportsCascadeDelete() 메소드 입니다.
1 2 3 4 | @Override public boolean supportsCascadeDelete() { return true; } | cs |
네, 결론적으로 MySQLDialect는 @OnDelete 어노테이션을 지원하지 않습니다. 제가 백날 함께 지워라.. 라고 정의한다 한들 DB에 접속해보면 한결같은 마리아디비님이시죠.
그러므로 InnoDB를 사용할 때는 application.properties의 dialect를 아래와 같이 변경해 줍니다.
1 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect | cs |
적용 후 Spring Boot를 재시작 하면 아래와 같이 ON DELETE : CASCADE로 변경되어 있는 것을 보실 수 있습니다.
예제 코드
1. Organization.java
A. 조직은 여러 개의 부서를 포함하고 있습니다.
B. 조직이 삭제되는 경우 @OnDelete에 의해 FK로 연결된 하위의 Department 데이터도 함께 삭제합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Getter @Setter @Entity @Table(name = "organization") public class Organization { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @OneToMany(mappedBy = "organization", cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER) @OnDelete(action = OnDeleteAction.CASCADE) private List<Department> departments = new ArrayList<>(); } | cs |
2. Department.java
부서는 조직에 속해있으며, 조직이 삭제될 때 함께 삭제되어야 합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Getter @Setter @Entity @Table(name = "department") public class Department { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ManyToOne @JoinColumn(name = "organization_id") private Organization organization; } | cs |
728x90
'Spring Boot' 카테고리의 다른 글
[튜토리얼] IntelliJ로 Hello World 찍기 (0) | 2022.08.08 |
---|---|
[아이디어] 복합키(Composite-key), 쉽게 CRUD 해보자 (0) | 2022.08.08 |
[Jackson] 순환참조 해결방법 (0) | 2022.08.05 |
[JPA] 빈 문자열을 null로 저장하는 converter 만들기 (0) | 2022.08.04 |
Spring JPA Envers 를 이용해 데이터의 변경이력 관리하기 (0) | 2019.03.01 |