Hibernate Envers查询_MOD列时列名不匹配问题求助
Hibernate Envers @Audited(withModifiedFlag=true) 列名不匹配问题的批量解决方案
我之前也遇到过类似的问题,结合你的场景(PostgreSQL + Hibernate 5.2.13 + Spring JPA默认命名策略),核心问题是Envers生成的_MOD列名和Spring命名策略转换后的查询列名不匹配,下面给你详细分析和批量解决办法:
问题复现
你的实体定义和生成的表结构完全对应了这个问题:
- 实体属性
fileName通过Spring命名策略转换为数据库列file_name - Envers生成的审计表中,modified列是
fileName_MOD(基于属性名直接加后缀) - 但查询时Envers会用转换后的列名加
_mod,即file_name_mod,导致PostgreSQL报错找不到列
根本原因
Spring的SpringPhysicalNamingStrategy会把Java驼峰命名转成数据库下划线小写格式,但Envers默认的DefaultModifiedColumnNamingStrategy是直接在实体属性名后拼接_MOD,而不是基于转换后的数据库列名生成modified列。这就造成了生成的列名和查询时期望的列名不一致。
批量解决方案
这里提供两种可靠的批量解决方式,你可以根据项目情况选择:
方式一:自定义Envers Modified列命名策略
通过实现Envers的ModifiedColumnNamingStrategy接口,让modified列名遵循Spring的命名规则:
- 实现自定义策略类
import org.hibernate.envers.configuration.ModifiedColumnNamingStrategy; import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; public class SpringEnversModifiedColumnNamingStrategy implements ModifiedColumnNamingStrategy { private final SpringPhysicalNamingStrategy physicalNamingStrategy = new SpringPhysicalNamingStrategy(); @Override public String getModifiedColumnName(String originalColumnName) { // 先让Spring策略处理原列名,再添加_mod后缀 Identifier originalId = Identifier.toIdentifier(originalColumnName); Identifier transformedId = physicalNamingStrategy.toPhysicalColumnName(originalId, null); return transformedId.getText() + "_mod"; } }
- 配置Hibernate使用该策略
在application.properties中添加:
hibernate.envers.modified_column_naming_strategy=com.yourpackage.SpringEnversModifiedColumnNamingStrategy
(替换com.yourpackage为你的实际包路径)
方式二:扩展Spring物理命名策略处理Envers列
如果方式一不生效,可以扩展SpringPhysicalNamingStrategy,让它自动修正Envers生成的_MOD列名:
- 扩展命名策略类
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; public class EnversAwareSpringPhysicalNamingStrategy extends SpringPhysicalNamingStrategy { @Override public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) { String columnName = name.getText(); // 识别Envers的modified列(以_MOD结尾) if (columnName.endsWith("_MOD")) { // 去掉_MOD后缀,用Spring策略转换基础名,再加_mod String baseName = columnName.substring(0, columnName.length() - 4); Identifier baseId = Identifier.toIdentifier(baseName); Identifier transformedBase = super.toPhysicalColumnName(baseId, context); return Identifier.toIdentifier(transformedBase.getText() + "_mod"); } return super.toPhysicalColumnName(name, context); } }
- 替换默认的物理命名策略
在application.properties中修改:
hibernate.physical_naming_strategy=com.yourpackage.EnversAwareSpringPhysicalNamingStrategy
临时方案(仅适用于少量实体)
如果只是个别实体需要审计,你可以手动指定modifiedColumnName:
@Column(name = "file_name") @Audited(withModifiedFlag = true, modifiedColumnName = "file_name_mod") private String fileName;
但显然这种方式在大量实体场景下不高效,还是推荐上面的批量解决方案。
内容的提问来源于stack exchange,提问作者andkov
相关产品推荐
相关产品推荐

