You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 01:25:03