MySQL

[MySQL] ON DELETE CASCADE: foreign key로 묶인 테이블의 레코드를 삭제할 때, 해당 레코드를 참조하는 다른 테이블의 레코드도 함께 자동으로 삭제하기

깃짱 2023. 5. 8. 13:10
반응형
 

💋 인트로

 

테스트 코드를 작성하는 도중에, 아래와 같은 에러를 만났다.

 

    @Test
    public void deleteProductTest() {
        RestAssured.given()

                .when()
                .delete("/admin/products/1")

                .then()
                .statusCode(HttpStatus.NO_CONTENT.value());
    }

 

Product를 지우고 나서 204 No Content 상태코드를 받는 테스트 코드이다. 

 

 

왜 발생한 에러지??

 

 

💋 문제 원인

 

DELETE /admin/products/1의 요청을 보내면, 아래 메서드가 실행된다.

 

    @DeleteMapping("admin/products/{id}")
    public ResponseEntity<Void> deleteProduct(@PathVariable long id) {
        deleteService.deleteProductBy(id);
        return ResponseEntity.noContent().build();
    }

 

여기서 호출하고 있는 deleteProductBy 메서드는 아래의 코드다.

 

@Service
public class ProductDeleteService {

    private final ProductDao productDao;

    public ProductDeleteService(final ProductDao productDao) {
        this.productDao = productDao;
    }

    @Transactional
    public void deleteProductBy(long id) {
        productDao.deleteById(id);
    }
}

 

DAO 구현체를 타고 들어가면

 

    @Override
    public void deleteById(long id) {
        String sql = "DELETE FROM product WHERE id = :id";
        Map<String, Long> parameter = Collections.singletonMap("id", id);

        namedParameterJdbcTemplate.update(sql, parameter);
    }

 

그치만 한 가지 문제가 있다!

나의 테이블 스키마를 보면, 아래와 같이 되어있다. 

 

DROP TABLE IF EXISTS cart;
DROP TABLE IF EXISTS product;
DROP TABLE IF EXISTS member;


CREATE TABLE PRODUCT
(
    id      BIGINT      NOT NULL AUTO_INCREMENT,
    name    VARCHAR(20) NOT NULL,
    img_url VARCHAR(255),
    price   INT         NOT NULL,
    PRIMARY KEY (id)
);
CREATE TABLE MEMBER
(
    id       BIGINT       NOT NULL AUTO_INCREMENT,
    email    VARCHAR(100) NOT NULL,
    password VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE CART
(
    id         BIGINT NOT NULL AUTO_INCREMENT,
    member_id  BIGINT NOT NULL,
    product_id BIGINT NOT NULL,
    FOREIGN KEY (member_id) REFERENCES MEMBER (id),
    FOREIGN KEY (product_id) REFERENCES PRODUCT (id),
    PRIMARY KEY (id)
);

 

내가 현재 지우려고 하는 Product 테이블은 Cart 테이블의 외래 키로 사용되고 있기 때문에 지울 수가 없다.

 

 

 

💋 해결 방법: CASCADE 옵션 사용

 

 

foreign key로 묶인 테이블의 레코드가 삭제될 때, 해당 레코드를 참조하는 다른 테이블의 레코드도 함께 자동으로 삭제된다.

foreign key 제약 조건을 설정할 때 ON DELETE CASCADE 옵션을 추가하면 된다.

 

 

CREATE TABLE CART
(
    id         BIGINT NOT NULL AUTO_INCREMENT,
    member_id  BIGINT NOT NULL,
    product_id BIGINT NOT NULL,
    FOREIGN KEY (member_id) REFERENCES MEMBER (id) ON DELETE CASCADE,
    FOREIGN KEY (product_id) REFERENCES PRODUCT (id) ON DELETE CASCADE,
    PRIMARY KEY (id)
);

 

 

이렇게 변경하니!

 

 

 

편-안

 

 

 

 

반응형