MySQL 8升级后@Enumerated(EnumType.STRING)枚举原生查询参数异常
MySQL 8.0.34升级后Hibernate原生查询枚举参数异常解决方案
将MySQL从5.7升级至8.0.34后,使用@Enumerated(EnumType.STRING)标注的枚举作为参数传入Hibernate原生查询时出现异常,该代码在MySQL 5.7环境下可正常运行。
代码示例
枚举类:
public enum MyEnum { A,B; }
实体类:
@Entity @Audited @Table(name = "my_table") public class MyTableModel { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true) private Long id; @Column(name = "myenum") @NotNull @Enumerated(EnumType.STRING) private MyEnum myEnum; // 其他字段和方法 }
报错的原生查询代码:
Query query = entityManager.createNativeQuery("UPDATE my_table up set up.myenum=:myenum WHERE up.id=:id "); query.setParameter("id", id); query.setParameter("myenum", MyEnum.B); query.executeUpdate();
不同版本报错信息
- Hibernate 4.2.21 + Spring 4.3.13:
Caused by: java.sql.SQLException: Incorrect string value: '\xAC\xED\x00\x05~r...' for column 'myenum' at row 1
- Hibernate 5.4.3 + Spring 5.3.27:
java.lang.IllegalArgumentException: No enum constant com.example.MyEnum.’~rFcom.example.MyEnumnxrjava.lang.EnumxptA at java.base/java.lang.Enum.valueOf(Enum.java:240) at org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor.fromName(EnumJavaTypeDescriptor.java:84)
已尝试操作
- 将参数改为
MyEnum.B.name()可正常运行,但需修改大量代码; - 验证数据库编码无问题;
- 更新Hibernate方言及MySQL Connector至8.0.15,问题仍未解决;
- 无法升级现有Hibernate/Spring版本。
解决方案
方案1:自定义Hibernate全局枚举类型(适配Hibernate 4.x)
自定义类型替代默认枚举序列化行为,自动将枚举转为字符串:
public class EnumStringType extends EnumType { @Override public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if (value == null) { st.setNull(index, Types.VARCHAR); } else { st.setString(index, ((Enum<?>) value).name()); } } }
在Hibernate配置文件中注册为全局默认枚举类型:
<hibernate-configuration> <session-factory> <!-- 其他配置 --> <typedef name="enum_string" class="com.yourpackage.EnumStringType"/> <property name="hibernate.type.preferred_enum_type">enum_string</property> </session-factory> </hibernate-configuration>
方案2:使用StatementInspector自动转换枚举参数(适配Hibernate 5.x)
自定义拦截器拦截PreparedStatement,自动将枚举参数转为字符串:
public class EnumStatementInspector implements StatementInspector { @Override public String inspect(String sql) { return sql; } @Override public void inspect(PreparedStatement st) throws SQLException { ParameterMetaData metaData = st.getParameterMetaData(); for (int i = 1; i <= metaData.getParameterCount(); i++) { try { Object value = st.getParameter(i); if (value instanceof Enum<?>) { st.setString(i, ((Enum<?>) value).name()); } } catch (Exception e) { // 保留原参数逻辑,忽略异常 } } } }
在Spring配置文件中启用该拦截器:
spring.jpa.properties.hibernate.session_factory.statement_inspector=com.yourpackage.EnumStatementInspector
方案3:包装EntityManager自动转换枚举参数(Spring环境通用)
自定义EntityManager包装类,在设置参数时自动转换枚举:
public class EnumAwareEntityManager extends EntityManagerDecorator { public EnumAwareEntityManager(EntityManager delegate) { super(delegate); } @Override public Query createNativeQuery(String sqlString) { Query delegateQuery = super.createNativeQuery(sqlString); return new EnumAwareQuery(delegateQuery); } private static class EnumAwareQuery extends QueryDecorator { public EnumAwareQuery(Query delegate) { super(delegate); } @Override public Query setParameter(String name, Object value) { if (value instanceof Enum<?>) { return super.setParameter(name, ((Enum<?>) value).name()); } return super.setParameter(name, value); } @Override public Query setParameter(int position, Object value) { if (value instanceof Enum<?>) { return super.setParameter(position, ((Enum<?>) value).name()); } return super.setParameter(position, value); } } }
在Spring中配置EntityManagerFactoryBean来包装EntityManager:
@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource); em.setPackagesToScan("com.yourpackage.entity"); em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); // 包装EntityManager实现自动转换 em.setPostProcessEntityManager(EnumAwareEntityManager::new); return em; }
内容的提问来源于stack exchange,提问作者ArturM
相关产品推荐
相关产品推荐

