Hibernate: insert into reply (id, board_id, content) values (null, ?, ?) o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [1] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [댓글1]
Hibernate: insert into reply (id, board_id, content) values (null, ?, ?) o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [1] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [댓글2]
그럼 삭제는 어떨까?
만약 cascade = CascadeType.PERSIST를 추가하지 않고 게시물을 저장할 때 처럼 BOARD(게시물)을 삭제하려 할 경우 BOARD만 삭제가 될 것이고 BOARD_ID가 foreign key로 걸려있는 REPLY(댓글)가 남아있기 때문에 SQL에서 오류가 날 것이다. foreign key가 걸려있는지는 역시 쿼리 로그를 통해 확인할 수 있다. (spring.jpa.hibernate.ddl-auto 속성의 값이 default는 create-drop 이기 때문에 해당 쿼리가 나온다.)
Hibernate: delete from reply where id=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [1]
Hibernate: delete from reply where id=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [2]
Hibernate: delete from board where id=? o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [1]
위 DELETE 쿼리를 날리기 전 해당 BOARD가 갖고 있는 REPLY를 찾기 위해 SELECT 문을 사용할 것이다. 총 4개의 SELECT 문을 사용하는데 @OneToMany의 default fet가 FetchType.LAZY이기 때문에 쿼리를 여러개 사용한다. 이 경우 아래와 같이 @OneToMany에 fetch = FetchType.EAGER 속성을 추가하면 쿼리문이 줄어들게 된다.
Hibernate: select board0_.id as id1_0_0_, board0_.title as title2_0_0_ from board board0_ where board0_.id=?
Hibernate: select reply0_.id as id1_1_0_, reply0_.board_id as board_id3_1_0_, reply0_.content as content2_1_0_, board1_.id as id1_0_1_, board1_.title as title2_0_1_ from reply reply0_ left outer join board board1_ on reply0_.board_id=board1_.id where reply0_.id=?
Hibernate: select reply0_.id as id1_1_0_, reply0_.board_id as board_id3_1_0_, reply0_.content as content2_1_0_, board1_.id as id1_0_1_, board1_.title as title2_0_1_ from reply reply0_ left outer join board board1_ on reply0_.board_id=board1_.id where reply0_.id=? Hibernate: select replylist0_.board_id as board_id3_1_0_, replylist0_.id as id1_1_0_, replylist0_.id as id1_1_1_, replylist0_.board_id as board_id3_1_1_, replylist0_.content as content2_1_1_ from reply replylist0_ where replylist0_.board_id=?
====게시물 삭제==== Hibernate: select board0_.id as id1_0_0_, board0_.title as title2_0_0_ from board board0_ where board0_.id=?
Hibernate: select replylist0_.board_id as board_id3_1_0_, replylist0_.id as id1_1_0_, replylist0_.id as id1_1_1_, replylist0_.board_id as board_id3_1_1_, replylist0_.content as content2_1_1_ from reply replylist0_ where replylist0_.board_id=?
지금은 쿼리 몇개의 차이밖에 없지만 만약 게시물의 댓글이 더 많다면 n + 1 문제의 영향을 받을 수 있기 때문에 지금의 케이스에서는 FetchType을 EAGER로 설정하는게 더 효과적이다. 하지만 실제 앱개발시에는 여러 상황을 고려해야하기 때문에 테스트를 거쳐 보다 안정적이고 효과적인 fetch type을 선택해야할 것이다.
삭제가 되는 것을 보고 ON DELETE CASCADE를 사용하는 건가? 라고 생각했었지만 콘솔에서 Table CREATE 쿼리를 확인했을 때 DB에서 Table에 ON DELETE CASCADE를 적용하는 건 아닌 것 같고 위 DELETE의 예제를 봤을 때 DELETE 쿼리를 생성하기 때문에 Hibernate에서 cascade를 관리하는 것 같다.