基于字段值将持久化实体设为不可变的Hibernate实现方案问询
基于字段值实现Hibernate实体不可变控制
一、标记实体不可变的方式
在实体类中添加映射到数据库的布尔字段,用来标识记录是否不可变,示例如下:
@Entity @Table(name = "business_data") public class BusinessData { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 不可变标记:true表示该记录禁止增删改 @Column(name = "is_immutable", nullable = false) private boolean immutable; // 其他业务字段 private String content; // getter/setter public boolean isImmutable() { return immutable; } public void setImmutable(boolean immutable) { this.immutable = immutable; } // 其余字段的getter/setter省略 }
二、阻止Hibernate执行增删改的原生方案
使用Hibernate的事件监听器替代旧版拦截器,通过PreInsertEventListener、PreUpdateEventListener、PreDeleteEventListener在操作执行前校验不可变标记,直接跳过对应操作,不会触发事务回滚或意外删除。
1. 实现自定义事件监听器
public class ImmutableEntityControlListener implements PreInsertEventListener, PreUpdateEventListener, PreDeleteEventListener { @Override public boolean onPreInsert(PreInsertEvent event) { return checkAndSkipImmutable(event.getEntity()); } @Override public boolean onPreUpdate(PreUpdateEvent event) { return checkAndSkipImmutable(event.getEntity()); } @Override public boolean onPreDelete(PreDeleteEvent event) { return checkAndSkipImmutable(event.getEntity()); } private boolean checkAndSkipImmutable(Object entity) { // 仅对目标实体类做校验 if (entity instanceof BusinessData) { BusinessData data = (BusinessData) entity; if (data.isImmutable()) { // 返回true告知Hibernate:该操作已处理,无需继续执行 return true; } } // 返回false:Hibernate正常执行后续操作 return false; } }
2. 注册监听器到Hibernate
根据项目环境选择注册方式:
Spring Boot 环境
通过HibernatePropertiesCustomizer注入监听器:
@Component public class HibernateListenerRegistrar implements HibernatePropertiesCustomizer { @Autowired private SessionFactory sessionFactory; @Override public void customize(Map<String, Object> hibernateProperties) { EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory) .getServiceRegistry().getService(EventListenerRegistry.class); registry.appendListeners(EventType.PRE_INSERT, new ImmutableEntityControlListener()); registry.appendListeners(EventType.PRE_UPDATE, new ImmutableEntityControlListener()); registry.appendListeners(EventType.PRE_DELETE, new ImmutableEntityControlListener()); } }
原生Hibernate 环境
在构建SessionFactory时注册:
Configuration config = new Configuration().configure(); config.setListener("pre-insert", new ImmutableEntityControlListener()); config.setListener("pre-update", new ImmutableEntityControlListener()); config.setListener("pre-delete", new ImmutableEntityControlListener()); SessionFactory sessionFactory = config.buildSessionFactory();
方案优势
- 覆盖全操作:同时拦截插入、更新、删除,解决setter仅能阻止更新的局限
- 无事务风险:通过返回true跳过操作,无需抛出异常,不会影响事务内其他合法操作
- 零业务侵入:无需在服务层或实体setter中编写校验逻辑,完全基于Hibernate原生机制实现
内容的提问来源于stack exchange,提问作者Jing Li
相关产品推荐
相关产品推荐

