使用UUID作为Varchar主键时Hibernate Envers无法持久化审计数据
Spring Boot + Hibernate Envers 下 UUID 主键配置问题解决
问题背景
使用Spring Boot 2.7.2、Hibernate 5.6.9.Final搭配MariaDB,实体主键定义为Varchar(255)类型存储UUID。启用Hibernate Envers后出现兼容性问题,Envers默认要求数值型ID或特殊配置才能支持UUID主键。尝试修改ID类型(String/UUID)、调整@GeneratedValue参数均未解决,出现两类典型报错:
报错1:保留@Type(type="uuid-char")时的异常
org.springframework.orm.jpa.JpaSystemException: The database returned no natively generated identity value; nested exception is org.hibernate.HibernateException: The database returned no natively generated identity value at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:331) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:566) ... Caused by: org.hibernate.HibernateException: The database returned no natively generated identity value at org.hibernate.id.IdentifierGeneratorHelper.getGeneratedIdentity(IdentifierGeneratorHelper.java:75) ... at org.hibernate.envers.internal.revisioninfo.DefaultRevisionInfoGenerator.saveRevisionData(DefaultRevisionInfoGenerator.java:67)
报错2:移除@Type(type="uuid-char")时的异常
org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259) ... Caused by: java.sql.SQLSyntaxErrorException: (conn=145) Incorrect string value: '\x97\x90@9\xA5d...' for column `erpm_db`.`number_directory_entry`.`id` at row 1 at org.mariadb.jdbc.export.ExceptionFactory.createException(ExceptionFactory.java:280) ...
最优解决方案
问题根源在于Envers默认使用的DefaultRevisionEntity采用数据库自增ID(IDENTITY策略),与当前UUID主键的配置冲突,导致保存修订信息时无法获取自增值。以下是无需升级依赖或修改现有主键类型的最优解决方法:
方案1:自定义Envers修订实体
- 创建自定义修订实体类
@Entity @Table(name = "REVINFO") @RevisionEntity @Getter @Setter public class CustomRevisionEntity { @Id @GeneratedValue(generator = "uuid") @Type(type = "uuid-char") @GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator") @Column(name = "REV", length = 36, nullable = false) private UUID id; @Column(name = "REVTSTMP", nullable = false) private Long timestamp; }
- 在Spring Boot配置中指定Envers使用该自定义实体
在application.properties中添加配置:
spring.jpa.properties.org.hibernate.envers.revision_entity_name=com.yourpackage.CustomRevisionEntity
方案2:调整Envers默认修订ID生成策略
若不想自定义实体,可通过配置修改Envers默认的修订ID生成策略,使其兼容UUID:
# 指定修订ID生成器为UUID生成器 spring.jpa.properties.org.hibernate.envers.revision_id_generator_strategy=org.hibernate.id.UUIDGenerator # 指定UUID生成策略(可选,默认即可) spring.jpa.properties.org.hibernate.envers.revision_id_generator_params=uuid_gen_strategy_class=org.hibernate.id.uuid.CustomVersionOneStrategy
关键注意事项
- 必须保留实体主键上的
@Type(type="uuid-char")注解,确保Hibernate将UUID以字符串形式存入Varchar字段,避免二进制存储导致的编码错误。 - 确保MariaDB方言配置正确:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
内容的提问来源于stack exchange,提问作者Hesam Karimian
相关产品推荐
相关产品推荐

