본문 바로가기
Develop/Spring+JPA

[JPA] @Where 무시하기

by 연로그 2023. 9. 11.
반응형

DB에서 데이터 삭제를 하기 위해서는 크게 hard delete와 soft delete가 존재한다.

  • hard delete: SQL의 DELETE문을 이용해 직접 데이터를 삭제하는 방법.
  • soft delete: SQL의 UPDATE문을 이용해 삭제 여부를 저장하는 컬럼을 변경하는 방법.

표준으로 정해진 것은 아니지만 soft delete는 일반적으로 deleted라는 컬럼에 true/false를 알 수 있는 값을 저장한다.

 

soft delete의 단점은 조회할 때마다 조회 조건을 추가하는게 매우 귀찮다. (일반적으로 조회는 삭제되지 않은 데이터들을 조회해야하니 where deleted = 0 같은 조건을 넣어야 한다.) 헌데 JPA에서는 정말 편리하게도 @Where라는 어노테이션을 제공해준다. @Where 클래스의 주석을 살펴보면 아래와 같다.

 

@Where annotation
Where clause to add to the element Entity or target entity of a collection. The clause is written in SQL. A common use case here is for soft-deletes.

 

 

엔티티에서 아래와 같이 @Where를 사용한다고 가정해보자.

@Entity
@Getter
@Where(clause = "deleted = 0")
@AllArgsConstructor
public class MemberInfo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;
    
    private String nickname;
}

 

Repository를 통해 findAll()을 호출하면 @Where에 추가한 deleted = 0 조건이 함께 호출된다.

select
    member_info0_.id as id1_11_,
    member_info0_.username as username2_11_,
    member_info0_.nickname as nickname3_11_
from
    member_info member_info0_ 
where (
    member_info0_.deleted = false
)

 

그렇다면 @Where를 무시하고 싶다면? 일반적으로 조회는 삭제되지 않는 데이터를 조회하는 경우가 많지만, 어드민 등에서 데이터 관리나 운영 목적으로 삭제된 데이터를 조회해야하는 경우도 있다. 

 

@Query를 사용해서 쿼리를 직접 선언해도 @Where의 deleted = 0 조건이 계속 호출된다.

@Transactional(readOnly = true)
public interface MemberInfoRepository extends JpaRepository<MemberInfo, Long> {

    @Query(value = "SELECT m.* FROM member_info m WHERE m.username = :username")
    List<MemberInfo> findByUsername(String username);
}

 

@Where를 무시하고 싶다면 nativeQuery = true 옵션을 함께 써주면 된다. 

@Transactional(readOnly = true)
public interface MemberInfoRepository extends JpaRepository<MemberInfo, Long> {

    @Query(value = "SELECT m.* FROM member_info m WHERE m.username = :username", nativeQuery = true)
    List<MemberInfo> findByUsername(String username);
}

 

native query를 직접 선언해서 실행하다 보면 JPA의 일부 장점들을 제대로 사용하지 못한다는 느낌이 있다. SQL을 직접 짜는 것 자체도 번거로운 일이고, SQL의 문법이 올바른지 실행 전에 확인하기 힘들다. 해당 쿼리가 특정 DB에만 종속되는 쿼리인지도 체크해보아야 한다.

 

하지만 아직까지 내가 사용해보기로는 복잡한 native query를 짤 일이 없고 DB 종류를 교체할 일이 없어 위의 단점들이 크게 와닿지 않았다. 위의 단점들보다 다른 조회 조건들에 where deleted = 0을 매번 붙여주는 것이 훨씬 번거로웠기 때문에 nativeQuery 옵션을 이용하는 것을 좀 더 선호하고 있다.

 


참고

반응형