[SPRING] 스프링 JPA로 소프트 삭제 처리하기
SPRING스프링 JPA로 소프트 삭제 처리하기
나는 테이블 항목을 다음과 같이 정의했다.
id, <fields>..., active
Active는 soft-delete 플래그이며 항상 1 또는 0입니다. 장기적으로 보면 이력 표가 없어 질 수 있습니다.
public interface StuffRepository extends JpaRepository<StuffEntity, Long> {}
코드에서는 항상 활성 레코드를 사용합니다. Spring이 항상이 저장소를 위해 생성 된 쿼리에 활성 = 1 조건을 추가하도록하는 방법이 있습니까? 또는 이상적으로는 쿼리를 생성하는 데 사용되는 문법을 확장 할 수 있습니까?
어디에서나 @ 큐 이름을 만들 수 있지만 생성 된 쿼리의 편의성을 잃어버린다는 것을 이해합니다. 또한 "활성"방법으로 인터페이스를 오염시키지 않으려합니다.
그게 중요하다면 내 JPA 구현으로 최대 절전 모드 4.2 사용하고 있습니다.
해결법
-
==============================
1.이것은 오래된 질문이며 이미 답을 찾았을 것입니다. 하지만, 스프링 / JPA / Hibernate 프로그래머가 대답을 구하는 모든 곳에서 -
이것은 오래된 질문이며 이미 답을 찾았을 것입니다. 하지만, 스프링 / JPA / Hibernate 프로그래머가 대답을 구하는 모든 곳에서 -
당신은 엔티티가 있다고해라 Dog :
@Entity public class Dog{ ......(fields).... @Column(name="is_active") private Boolean active; }
저장소 :
public interface DogRepository extends JpaRepository<Dog, Integer> { }
엔티티 레벨에 @Where 주석을 추가하면됩니다.
@Entity @Where(clause="is_active=1") public class Dog{ ......(fields).... @Column(name="is_active") private Boolean active; }
저장소가 수행하는 모든 쿼리는 자동으로 "비활성"행을 필터링합니다.
-
==============================
2.@Where (clause = "is_active = 1")는 스프링 데이터 jpa로 소프트 삭제를 처리하는 가장 좋은 방법은 아닙니다.
@Where (clause = "is_active = 1")는 스프링 데이터 jpa로 소프트 삭제를 처리하는 가장 좋은 방법은 아닙니다.
첫째, 최대 절전 모드 구현에서만 작동합니다.
둘째, 스프링 데이터로 소프트 삭제 된 엔티티를 가져올 수 없습니다.
내 솔루션은 봄 데이터에 의해 제공됩니다. # {# entityName} 표현식은 구체적인 저장소 유형 이름을 나타내는 일반 저장소에서 사용할 수 있습니다.
코드는 다음과 같습니다.
//Override CrudRepository or PagingAndSortingRepository's query method: @Override @Query("select e from #{#entityName} e where e.deleteFlag=false") public List<T> findAll(); //Look up deleted entities @Query("select e from #{#entityName} e where e.deleteFlag=true") public List<T> recycleBin(); //Soft delete. @Query("update #{#entityName} e set e.deleteFlag=true where e.id=?1") @Modifying public void softDelete(String id);
-
==============================
3.답변을 바탕으로 softdleep에 대한 재정의 된 메소드를 사용하여 CrudRepository 구현을 만들었습니다.
답변을 바탕으로 softdleep에 대한 재정의 된 메소드를 사용하여 CrudRepository 구현을 만들었습니다.
@NoRepositoryBean public interface SoftDeleteCrudRepository<T extends BasicEntity, ID extends Long> extends CrudRepository<T, ID> { @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.isActive = true") List<T> findAll(); @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id in ?1 and e.isActive = true") Iterable<T> findAll(Iterable<ID> ids); @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id = ?1 and e.isActive = true") T findOne(ID id); //Look up deleted entities @Query("select e from #{#entityName} e where e.isActive = false") @Transactional(readOnly = true) List<T> findInactive(); @Override @Transactional(readOnly = true) @Query("select count(e) from #{#entityName} e where e.isActive = true") long count(); @Override @Transactional(readOnly = true) default boolean exists(ID id) { return findOne(id) != null; } @Override @Query("update #{#entityName} e set e.isActive=false where e.id = ?1") @Transactional @Modifying void delete(Long id); @Override @Transactional default void delete(T entity) { delete(entity.getId()); } @Override @Transactional default void delete(Iterable<? extends T> entities) { entities.forEach(entitiy -> delete(entitiy.getId())); } @Override @Query("update #{#entityName} e set e.isActive=false") @Transactional @Modifying void deleteAll(); }
BasicEntity와 함께 사용할 수 있습니다.
@MappedSuperclass public abstract class BasicEntity { @Column(name = "is_active") private boolean isActive = true; public abstract Long getId(); // isActive getters and setters... }
그리고 마지막 엔티티 :
@Entity @Table(name = "town") public class Town extends BasicEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "town_id_seq") @SequenceGenerator(name = "town_id_seq", sequenceName = "town_id_seq", allocationSize = 1) protected Long id; private String name; // getters and setters... }
-
==============================
4.현재 버전 (최대 1.4.1)에는 Spring Data JPA의 소프트 삭제를위한 전용 지원이 없습니다. 그러나 DATAJPA-307의 피쳐 브랜치는 현재 출시 예정인 기능이기 때문에 사용을 권장합니다.
현재 버전 (최대 1.4.1)에는 Spring Data JPA의 소프트 삭제를위한 전용 지원이 없습니다. 그러나 DATAJPA-307의 피쳐 브랜치는 현재 출시 예정인 기능이기 때문에 사용을 권장합니다.
현재 상태를 사용하려면 1.5.0.DATAJPA-307-SNAPSHOT까지 사용하는 버전을 업데이트하고 작동해야하는 특수 스프링 데이터 공유 버전을 가져 오도록하십시오. 테스트 결과를 얻는 방법을 알아야하는 샘플 테스트 케이스를 따라 할 수 있어야합니다.
P.S .: 기능에 대한 작업이 끝나면 질문을 업데이트하겠습니다.
-
==============================
5.SimpleJpaRepository에서 확장하고 일반적인 방식으로 소프트 삭제 기능을 정의 할 수있는 사용자 정의 리포지토리를 만들 수 있습니다.
SimpleJpaRepository에서 확장하고 일반적인 방식으로 소프트 삭제 기능을 정의 할 수있는 사용자 정의 리포지토리를 만들 수 있습니다.
커스텀 JpaRepositoryFactoryBean을 생성하고 메인 클래스에서 활성화 할 필요가 있습니다.
내 코드는 여기에서 확인할 수 있습니다. https://github.com/dzinot/spring-boot-jpa-soft-delete
-
==============================
6.최대 절전 모드 특정 주석을 가져 오지 않으려는 경우 데이터베이스보기 (또는 Oracle의 해당 기능)를 사용하는 것이 좋습니다. mySQL 5.5에서 필터 기준이 active = 1처럼 단순 할 경우 이러한보기를 업데이트하고 삽입 할 수 있습니다.
최대 절전 모드 특정 주석을 가져 오지 않으려는 경우 데이터베이스보기 (또는 Oracle의 해당 기능)를 사용하는 것이 좋습니다. mySQL 5.5에서 필터 기준이 active = 1처럼 단순 할 경우 이러한보기를 업데이트하고 삽입 할 수 있습니다.
이것이 좋은 아이디어인지는 아마 당신의 데이터베이스에 달려있다. 그러나 그것은 나의 구현에서 훌륭하게 작동한다.
삭제를 취소하려면 직접 'Stuff'에 액세스 한 엔티티가 필요하지만 그 다음에는 @Where가 필요합니다.
-
==============================
7.@vadim_shb의 솔루션을 사용하여 JpaRepository를 확장했으며 여기에 스칼라 코드가 포함되어 있습니다. 그의 대답을 upvote,이 하나가 아닙니다. 페이징과 정렬을 포함하는 예제를 보여 주기만하면됩니다.
@vadim_shb의 솔루션을 사용하여 JpaRepository를 확장했으며 여기에 스칼라 코드가 포함되어 있습니다. 그의 대답을 upvote,이 하나가 아닙니다. 페이징과 정렬을 포함하는 예제를 보여 주기만하면됩니다.
페이징 및 정렬은 쿼리 주석과 함께 잘 작동합니다. 모든 것을 테스트하지는 않았지만 페이징 및 정렬에 대해 묻는 사람들은 Query 주석 맨 위에 레이어 된 것처럼 보입니다. 문제가 해결되면 더 자세히 업데이트하겠습니다.
import java.util import java.util.List import scala.collection.JavaConverters._ import com.xactly.alignstar.data.model.BaseEntity import org.springframework.data.domain.{Page, Pageable, Sort} import org.springframework.data.jpa.repository.{JpaRepository, Modifying, Query} import org.springframework.data.repository.NoRepositoryBean import org.springframework.transaction.annotation.Transactional @NoRepositoryBean trait BaseRepository[T <: BaseEntity, ID <: java.lang.Long] extends JpaRepository[T, ID] { /* additions */ @Query("select e from #{#entityName} e where e.isDeleted = true") @Transactional(readOnly = true) def findInactive: Nothing @Transactional def delete(entity: T): Unit = delete(entity.getId.asInstanceOf[ID]) /* overrides */ @Query("select e from #{#entityName} e where e.isDeleted = false") override def findAll(sort: Sort): java.util.List[T] @Query("select e from #{#entityName} e where e.isDeleted = false") override def findAll(pageable: Pageable): Page[T] @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.isDeleted = false") override def findAll: util.List[T] @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id in :ids and e.isDeleted = false") override def findAll(ids: java.lang.Iterable[ID]): java.util.List[T] @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id = :id and e.isDeleted = false") override def findOne(id: ID): T @Transactional(readOnly = true) @Query("select count(e) from #{#entityName} e where e.isDeleted = false") override def count: Long @Transactional(readOnly = true) override def exists(id: ID): Boolean = findOne(id) != null @Query("update #{#entityName} e set e.isDeleted=true where e.id = :id") @Transactional @Modifying override def delete(id: ID): Unit @Transactional override def delete(entities: java.lang.Iterable[_ <: T]): Unit = { entities.asScala.map((entity) => delete(entity)) } @Transactional @Modifying override def deleteInBatch(entities: java.lang.Iterable[T]): Unit = delete(entities) override def deleteAllInBatch(): Unit = throw new NotImplementedError("This is not implemented in BaseRepository") @Query("update #{#entityName} e set e.isDeleted=true") @Transactional @Modifying def deleteAll(): Unit }
from https://stackoverflow.com/questions/19323557/handling-soft-deletes-with-spring-jpa by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring @ContextConfiguration XML에 올바른 위치를 두는 법 (0) | 2018.12.11 |
---|---|
[SPRING] Spring - 동일한 애플리케이션에서 여러 트랜잭션 관리자를 사용할 수 있습니까? (0) | 2018.12.11 |
[SPRING] 스프링 MVC - @RequestBody와 @RequestParam을 함께 사용할 수없는 이유 (0) | 2018.12.11 |
[SPRING] "@Transactional"은 서비스 레이어 또는 DAO에 있어야합니다. (0) | 2018.12.11 |
[SPRING] 스프링의 순환 의존성 (0) | 2018.12.11 |