실제 현업에서는 삭제되는 데이터를 데이터베이스에서 지우지 않는다. isDelete 속성을 true로 바꾸거나 deleteAt, deleteBy 속성으로 관리한다. 그렇다면 삭제된 데이터를 제외하고 검색하려면 어떻게 해야할까?
효율성은 상황에 따라 달라질 수 있으므로 상황에 따라 적합한 방식을 선택하면 된다. JPQL 또는 Criteria API는 유연하고 복잡한 쿼리 작성에 적합하며, specification또는 querydsl은 동적 쿼리가 필요한 경우에 적합하다. @Where 애너테이션은 간단하고 자동화된 필터링이 필요시에 유용하지만 hibernate-specific이다. 쿼리메서드의 경우 가장 간단하고 직관적인 방법으로, 기본적인 조건 검색에 효율적이다.
@Query 애너테이션을 사용하여 JPQL 쿼리를 작성하거나 Criteria API를 사용하여 동적으로 쿼리를 생성한다. 이 방법은 직접 쿼리를 작성하기 때문에 유연하고 성능이 좋을 수 있다.
public interface HubRepository extends JpaRepository<Hub, Long> {
@Query("SELECT h FROM Hub h WHERE h.isDelete = false")
List<Hub> findAllActiveHubs();
}
public List<Hub> findAllActiveHubs() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Hub> query = cb.createQuery(Hub.class);
Root<Hub> root = query.from(Hub.class);
query.select(root).where(cb.equal(root.get("isDelete"), false));
return entityManager.createQuery(query).getResultList();
}
Hibernate에서는 @SQLRestriction 애너테이션을 사용하여 특정 조건을 자동으로 추가할 수 있다. 이 방법은 데이터베이스 쿼리에서 isDelete가 false인 레코드만 가져오도록 자동으로 필터링한다. 이 방법은 Hibernate-specific이므로 다른 JPA 구현체에서는 지원되지 않을 수 있다.
import org.hibernate.annotations.Where;
@Entity
@SQLRestriction("is_delete IS FALSE")
출처: https://jaeseo0519.tistory.com/375 [코드를 찢다:티스토리]
public class Hub {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private boolean isDelete;
}
Spring Data JPA의 Specification 또는 Querydsl을 사용하여 동적으로 쿼리를 작성할 수 있습니다. 이 방법은 복잡한 쿼리를 동적으로 생성할 수 있는 장점이 있습니다.
import org.springframework.data.jpa.domain.Specification;
public class HubSpecifications {
public static Specification<Hub> isActive() {
return (root, query, cb) -> cb.equal(root.get("isDelete"), false);
}
}
public interface HubRepository extends JpaRepository<Hub, Long>, JpaSpecificationExecutor<Hub> {
}
public List<Hub> findAllActiveHubs() {
return hubRepository.findAll(HubSpecifications.isActive());
}
Spring Data JPA의 쿼리 메서드를 사용하여 조건을 지정할 수 있다. 기본적인 방법이며, 간단한 조건에서는 매우 효율적이다.
public interface HubRepository extends JpaRepository<Hub, Long> {
List<Hub> findByIsDeleteFalse();
}
@Query 어노테이션에 nativeQuery = true 속성을 추가하여, SQL을 직접 작성함으로써 @SQLRestriction 조건을 우회할 수 있다.
(@Query를 사용한 JPQL로는 불가능하다.)
@Query(value = "SELECT * FROM delivery_user du WHERE du.user_id = :userId", nativeQuery = true)
Optional<DeliveryUser> findByUserIgnoreIsDelete(@Param("userId") Long userId);
EntityManager를 사용하여 커스텀 쿼리를 실행하면, 엔티티에 설정된 @SQLRestriction 조건이 적용되지 않는다.
@Autowired
private EntityManager entityManager;
public DeliveryUser findUserIgnoreDelete(Long userId) {
String query = "SELECT du FROM DeliveryUser du WHERE du.user.id = :userId";
return entityManager.createQuery(query, DeliveryUser.class)
.setParameter("userId", userId)
.getSingleResult();
}
Spring Data JPA의 Specification을 사용해 동적으로 조건을 빼거나 추가할 수 있다. 이 경우에도 @Where 조건은 무시된다.
public Optional<DeliveryUser> findUserIgnoreDelete(User user) {
return deliveryUserRepository.findOne((root, query, cb) -> {
return cb.equal(root.get("user"), user);
});
}