Spring Data 是個好東西,極大簡化了后端dao的操作,只需要在 dao 接口寫個 findByXXX 的方法就能自動實現按條件查詢這個簡直太爽了。但是在實際使用過程中,可能會遇到一個持久化邏輯刪除的問題。那么問題來了。spring data jpa並不支持邏輯刪除。那如何處理?
在互聯網項目中,通常刪除都不是物理刪除,而是邏輯刪除。
那么在展示數據的時候需要過濾掉已刪除的數據。而@Where 注解可以說就是為此而設計的。
package org.hibernate.annotations; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * 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. * * @author Emmanuel Bernard */ @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME) public @interface Where { /** * The where-clause predicate. */ String clause(); }
這玩意兒乍一看很美好。但是實際不然。這樣做將所有的刪除方法都覆蓋了。當我想要用到物理刪除的時候。就不能用了。於是再次出發。尋找一種更加美妙的解決方案。終於讓我找到了。話不多說。直接放碼。
@NoRepositoryBean public interface BaseDao<T extends BaseEntry, ID extends Serializable> extends PagingAndSortingRepository<T, ID> { @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.deleted = false") List<T> findAll(); @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id in ?1 and e.deleted = false") Iterable<T> findAll(Iterable<ID> ids); @Override @Transactional(readOnly = true) @Query("select e from #{#entityName} e where e.id = ?1 and e.deleted = false") T findOne(ID id); @Override @Transactional(readOnly = true) @Query("select count(e) from #{#entityName} e where e.deleted = false") long count(); @Override @Transactional(readOnly = true) default boolean exists(ID id) { return findOne(id) != null; } @Query("update #{#entityName} e set e.deleted = true where e.id = ?1") @Transactional @Modifying void logicDelete(ID id); @Transactional default void logicDelete(T entity) { logicDelete((ID) entity.getId()); } @Transactional default void logicDelete(Iterable<? extends T> entities) { entities.forEach(entity -> logicDelete((ID) entity.getId())); } @Query("update #{#entityName} e set e.deleted = true ") @Transactional @Modifying void logicDeleteAll(); }
BaseEntry代碼如下:
@Data @MappedSuperclass public class BaseEntry implements Serializable { private static final long serialVersionUID = 5966306766659220492L; @Id protected String id; @Temporal(TemporalType.TIMESTAMP) protected Date createdDate; protected String createdBy; @Temporal(TemporalType.TIMESTAMP) protected Date updatedDate; protected String updatedBy; protected Boolean deleted = false; }