Hibernate 6.3中@Where和@Loader注解的非弃用替代方案咨询
Hibernate 6.3+ 非弃用软删除实现方案
针对Hibernate 6.3起org.hibernate.annotations.Where和Loader被弃用的情况,替代原@NamedQuery+@SQLDelete的软删除方案有以下几种,均为官方推荐的非弃用方式:
1. 最简方案:使用Hibernate @SoftDelete注解
Hibernate 6.2及以上版本引入了@SoftDelete注解,直接封装了软删除的核心逻辑,无需手动编写删除SQL和过滤规则:
@Entity // 配置软删除字段、已删除/未删除对应的值 @SoftDelete( columnName = "is_deleted", deletedValue = "true", notDeletedValue = "false" ) public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 软删除字段,会被@SoftDelete自动维护 private Boolean isDeleted; // 其他业务字段... }
- 执行删除:调用
entityManager.remove(product)时,Hibernate自动执行UPDATE product SET is_deleted = true WHERE id = ?,而非物理删除; - 查询过滤:所有JPQL/Criteria查询会自动过滤掉
is_deleted = true的记录,无需额外编写条件。
2. 灵活控制方案:@SQLDelete + Hibernate @Filter & @FilterDefinition
如果需要动态控制是否过滤已删除数据,或者兼容部分旧逻辑,可以保留@SQLDelete,用@Filter替代原@Where注解:
第一步:实体类配置
// 定义过滤器参数和规则 @FilterDef( name = "excludeDeleted", parameters = @ParamDef(name = "deletedStatus", type = Boolean.class) ) // 绑定过滤器到实体,指定过滤条件 @Filter( name = "excludeDeleted", condition = "is_deleted = :deletedStatus" ) @Entity // 自定义删除SQL,替换为更新软删除字段 @SQLDelete(sql = "UPDATE product SET is_deleted = true WHERE id = ?") public class Product { @Id private Long id; private Boolean isDeleted = false; // 其他业务字段... }
第二步:启用过滤器
在需要过滤已删除数据的会话中启用过滤器:
// 获取Hibernate Session Session session = entityManager.unwrap(Session.class); // 启用过滤器并设置参数(只查询未删除数据) session.enableFilter("excludeDeleted") .setParameter("deletedStatus", false);
- 优势:可根据业务场景动态开关过滤器(比如管理员需要查看已删除数据时,将参数设为
true即可)。
3. 复杂逻辑方案:自定义实体监听器
如果软删除时需要额外处理其他业务逻辑(比如更新删除时间、同步关联表状态),可以用JPA生命周期注解实现:
第一步:定义软删除接口(统一规范,可选)
public interface SoftDeletable { void setDeleted(boolean deleted); void setDeletedAt(LocalDateTime deletedAt); }
第二步:实现实体监听器
public class SoftDeleteListener { @PreRemove public void handleSoftDelete(Object entity) { if (entity instanceof SoftDeletable) { SoftDeletable deletable = (SoftDeletable) entity; // 设置软删除标记和删除时间 deletable.setDeleted(true); deletable.setDeletedAt(LocalDateTime.now()); // 将删除操作转为更新操作 EntityManager em = PersistenceUtil.getEntityManager(); em.merge(deletable); // 抛出异常阻止物理删除(Hibernate会捕获并执行更新) throw new RuntimeException("Soft delete triggered, physical deletion prevented"); } } }
第三步:绑定到实体类
@Entity @EntityListeners(SoftDeleteListener.class) public class Product implements SoftDeletable { @Id private Long id; private Boolean isDeleted = false; private LocalDateTime deletedAt; // 实现接口方法 @Override public void setDeleted(boolean deleted) { this.isDeleted = deleted; } @Override public void setDeletedAt(LocalDateTime deletedAt) { this.deletedAt = deletedAt; } }
- 查询时:需要在JPQL/Criteria查询中手动添加
WHERE isDeleted = false条件,或者用@NamedQuery定义带过滤的查询(原@NamedQuery仍可正常使用)。
内容的提问来源于stack exchange,提问作者Raymond Domingo
相关产品推荐
相关产品推荐

