Hibernate Envers插入新记录后自动删除的问题求助
聊聊Hibernate Envers插入新记录后自动删除的坑
最近你遇到的这个问题挺典型的——本地好好的,一到SIT环境就出现插入后自动删除,还返回成功提示,确实挺头疼的。我结合自己的经验和对Envers的理解,给你拆解下:
问题场景回顾
咱们项目用Hibernate Envers做表审计,Configuration实体加了@Audited注解,本地用JPARepository.save()增删改都正常,但到了SIT环境,创建新配置时系统提示成功,却在列表里找不到记录。查日志发现流程是:先插CONFIG表,然后写REVINFO和CONFIG_AUD审计记录,接着执行查询,最后又把刚插的CONFIG记录删掉,还写了删除的审计日志,CONFIG_AUD里有插入和删除两条记录。
为啥Envers会在插入后删记录?回滚触发原因是什么?
首先得明确:Envers本身不会主动删你的记录,这事儿本质是事务回滚导致的。Envers会完整记录事务内的所有操作,包括回滚前的插入,以及回滚时的删除操作,所以你才会在审计表里看到两条对应记录。
结合环境差异,触发回滚的可能原因有这些:
- 数据库约束冲突:SIT库的CONFIG表大概率有本地没有的约束——比如某个字段加了唯一键,你插入的新记录值重复了;或者外键关联的表没有对应数据。但因为某些原因,这个异常没抛到上层,导致事务悄悄回滚了。
- 事务配置差异:本地和SIT的Spring事务配置不一样,比如事务传播特性、超时时间。比如SIT的事务超时时间更短,插入时因为数据库锁或者网络延迟超时了,触发回滚;或者嵌套事务的配置导致子事务回滚影响了主事务。
- 实体继承的坑:你的
Configuration继承了DetailedAuditEntity,如果父类有Envers相关的配置(比如继承策略),而SIT环境的Hibernate版本和本地不同,可能导致Envers处理继承时出问题,触发隐性回滚。 - 序列权限问题:你的主键用了序列
CONFIG_SEQ,如果SIT的应用账号没有序列的nextval权限,插入时主键生成失败,也会触发回滚——不过这种情况一般会抛异常,可能性稍低。
为啥回滚了还返回成功?没抛异常?
这十有八九是代码里的异常处理把回滚的异常吞了,还硬返回了成功提示。比如这种坑人的代码:
try { configRepository.save(config); return "Record created successfully"; } catch (Exception e) { // 只打了日志,没抛异常也没返回错误 log.error("Save failed", e); return "Record created successfully"; }
另外,也可能是事务管理器的配置问题:比如SIT的事务配置忽略了某些检查型异常,导致事务回滚但上层没感知到。记住,Envers的操作是绑定在主事务里的,主事务回滚时,Envers会记录回滚的操作,但如果主事务的异常被吞了,前端就会收到错误的成功提示。
只在SIT出现,是不是配置问题?
绝对是环境配置差异导致的,重点查这几个点:
- 数据库结构差异:对比本地和SIT的CONFIG表结构,看有没有新增的唯一键、外键、非空约束,或者字段类型不一致。
- 依赖版本差异:检查pom.xml/gradle里的Hibernate、Envers、Spring Boot版本,本地和SIT是不是一致——有些Envers的bug只在特定版本触发。
- 事务配置差异:看Spring事务管理器的配置,比如事务隔离级别、传播特性、超时时间,本地和SIT有没有区别。
- 缓存配置:SIT是不是开了二级缓存,而本地没开?缓存同步问题可能导致插入后查询不到,触发代码里的重试或回滚逻辑。
排查步骤建议
- 先查SIT库的表约束:用
desc CONFIG或者数据库管理工具对比本地和SIT的表结构,重点看约束规则。 - 检查代码的事务和异常处理:找到保存配置的方法,看看有没有吞异常的逻辑,有没有正确处理事务回滚的情况。
- 开Hibernate的DEBUG日志:把
org.hibernate和org.springframework.transaction的日志级别调到DEBUG,看事务什么时候触发回滚,有没有隐藏的SQL报错。 - 对比依赖版本:确保本地和SIT的依赖完全一致,避免版本差异导致的兼容问题。
- 检查父类
DetailedAuditEntity:看父类有没有Envers相关的注解,比如@NotAudited或者@Audited的继承配置,是不是在不同环境下有不同的处理。
内容的提问来源于stack exchange,提问作者sml485
相关产品推荐
相关产品推荐

