带有@Audited注解的实体中ZoneId类型字段引发Hibernate映射异常问题求助
解决Hibernate Envers审计表中ZoneId字段类型映射问题
这个问题我之前也帮不少开发者排查过——本质是Hibernate(包括负责审计的Envers模块)默认没有内置ZoneId类型到数据库列的映射规则。当你给实体加上@Audited注解后,Envers会自动生成对应的审计表(比如这里的manager_company_relation_aud),但它识别不了ZoneId这个Java类型对应的数据库字段类型,所以直接抛出了MappingException。
下面给你两种靠谱的解决办法,按需选就行:
方法1:用Hibernate内置的ZoneId类型映射(推荐,Hibernate 5.2+可用)
Hibernate从5.2版本开始内置了ZoneIdType,专门处理ZoneId和数据库字符串的转换,直接在字段上加@Type注解就行:
import org.hibernate.annotations.Type; import javax.persistence.Entity; import org.hibernate.envers.Audited; import java.time.ZoneId; @Entity @Audited public class ManagerCompanyRelation { // 其他字段省略... @Type(type = "org.hibernate.type.ZoneIdType") private ZoneId timezone; // getter、setter方法... }
加完这个注解后,Hibernate会自动把ZoneId序列化为类似"Asia/Shanghai"的字符串,存在数据库的VARCHAR列里;查询时再反序列化成ZoneId对象。Envers生成的审计表也会自动沿用这个规则,不会再报类型识别错误。
方法2:自定义AttributeConverter(兼容低版本Hibernate)
如果你的Hibernate版本低于5.2,或者需要更灵活的转换逻辑,就自己写个转换器:
- 先创建转换器类,实现
AttributeConverter接口:
import javax.persistence.AttributeConverter; import javax.persistence.Converter; import java.time.ZoneId; @Converter(autoApply = true) // 设为true的话,所有ZoneId类型的字段都会自动用这个转换规则 public class ZoneIdConverter implements AttributeConverter<ZoneId, String> { @Override public String convertToDatabaseColumn(ZoneId zoneId) { return zoneId != null ? zoneId.getId() : null; } @Override public ZoneId convertToEntityAttribute(String dbData) { return dbData != null ? ZoneId.of(dbData) : null; } }
- 然后实体类里的字段就不用额外加注解了(因为
autoApply=true);如果不想全局生效,也可以单独给字段加@Convert(converter = ZoneIdConverter.class):
@Entity @Audited public class ManagerCompanyRelation { // 其他字段省略... // 如果autoApply=false,就加这个注解指定转换器 // @Convert(converter = ZoneIdConverter.class) private ZoneId timezone; // getter、setter方法... }
这种方式不仅主表能正确映射,Envers的审计表也会继承这个转换规则,完美解决问题。
小提醒
- 要是用方法1,记得确认Hibernate版本是5.2及以上,不然找不到
ZoneIdType; - 审计表的字段类型会和主表保持一致,所以只要主表的
ZoneId映射搞定了,审计表就不会出问题。
内容的提问来源于stack exchange,提问作者Sergo
相关产品推荐
相关产品推荐

