1. 레파지토리
@Transactional public void deleteById(int id){ Query query = em.createQuery("delete from Board b where b.id =:id"); query.setParameter("id",id); query.executeUpdate(); //버전2보다 버전1 추천. 여기는 삭제 기능만 처리되고, 조회는 서비스 레이어에서 하는게 맞음 } @Transactional public void deleteByIdV2(int id){ //우선 조회를 하면 pc에 데이터가 남아있기 때문에삭제할 수 있음 Board board =findById(id); em.remove(board); //pc에 객체를 지우고, 트랜잭션 종료시 쿼리가 전송됨. }
삭제 메서드로 두 가지 버전을 만들었다. 버전1은 JPQL 을 사용해 직접 쿼리를 작성했고 , 버전 2는 JPA 에서 제공하는
remove
메서드를 사용했다. 2. JUnit 테스트
버전1
@Test public void deleteByIdV1_test(){ int id = 1; boardReposiroty.deleteById(id); }
버전 1을 사용하면 정상적으로 delete 쿼리가 전송된다.
버전2
@Test public void deleteByIdV2_test(){ int id = 1; boardReposiroty.deleteByIdV2(id); }
버전2를 사용하면 select 쿼리만 발동되고 delete 쿼리는 발동되지 않는다.
트랜잭션 내부에 있는 쿼리는 트랜잭션이 완료된 이후에 PC에서 DB 로 쿼리가 전송된다.
하지만 JUnit 테스트에서는
@Test
내부에도 트랜잭션이 있기 때문에 이중 트랜잭션이 된다. 따라서 delete 메서드 내부의 트랜잭션이 종료되더라도, JUnit 내부의 트랜잭션이 종료되지 않고, JUnit이 종료되면 프로그램 실행이 종료되기 때문에 따로 쿼리가 전달되지 않는다.findById 메서드로 객체를 조회하지만 테스트 코드에서는 쿼리가 전달되지 않기 때문에 PC 메모리에서만 데이터가 제거되고, DB 에는 유지된다. 만약 테스트에서 delete 쿼리를 전달하고 싶다면 flush메서드를 사용하면 된다.
@Test public void deleteByIdV2_test(){ int id = 1; boardReposiroty.deleteByIdV2(id); em.flush(); }
flush()를 사용해 강제로 쿼리를 전송한다.
3. 컨트롤
@PostMapping("/board/{id}/delete") public String delete(@PathVariable Integer id){ boardPersistRepository.deleteById(id); return "redirect:/"; }
삭제 할 때는 remove 메서드보다 쿼리를 작성하는 버전1을 사용하기로 한다. 레파지토리에선 삭제만 실행하고, 조회는 다른 레이어에서 해야 트랜잭션의 길이가 줄어들기 때문이다.
Share article