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

MySQL与Java:带描述的枚举存储及JdbcTemplate异常处理求助

我之前做项目的时候也碰到过一模一样的问题,给你分享下我的解决方案:

问题1:数据库应该存储什么值?

强烈建议你存储ACTIVE/AWAITING这种枚举的短标识,而不是Active Order/Awaiting Order这种显示文本,原因有这几点:

  • 避免数据截断:你遇到的异常大概率是因为数据库字段长度不够(比如设了VARCHAR(10)),而Active Order这类文本长度超过了限制。短标识长度固定且短,完全不会有这个问题。
  • 数据稳定性:显示文本以后可能需要修改(比如改成"Active Order Item"),但枚举的业务标识(ACTIVE)不会变,存标识的话不需要修改数据库里的历史数据。
  • 语义明确:ACTIVE这类标识对开发者更友好,看数据库数据就能直接知道状态含义,不需要额外映射。

如果需要给用户显示友好名称,只需要在枚举里定义对应的显示属性,查询后再转换就行(比如给枚举加个displayName字段,调用getDisplayName()获取)。

问题2:JdbcTemplate结合MapSqlParameterSource保存枚举值

分两种常见场景来处理:

场景1:直接存储枚举的name()(推荐)

假设你的枚举定义是这样的:

public enum OrderStatus {
    ACTIVE("Active Order"),
    AWAITING("Awaiting Order");

    private final String displayName;

    OrderStatus(String displayName) {
        this.displayName = displayName;
    }

    public String getDisplayName() {
        return displayName;
    }
}

保存时,直接把枚举的name()作为参数传入MapSqlParameterSource:

String insertSql = "INSERT INTO orders (id, status) VALUES (:orderId, :orderStatus)";

MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("orderId", 123L);
// 传入枚举的name(),对应数据库里的ACTIVE/AWAITING
params.addValue("orderStatus", orderStatus.name());

jdbcTemplate.update(insertSql, params);

查询时,把数据库返回的字符串转回枚举:

String querySql = "SELECT id, status FROM orders WHERE id = :orderId";

Order result = jdbcTemplate.queryForObject(querySql, 
    new MapSqlParameterSource("orderId", 123L),
    (rs, rowNum) -> {
        Order order = new Order();
        order.setId(rs.getLong("id"));
        // 用valueOf把字符串转成枚举
        order.setStatus(OrderStatus.valueOf(rs.getString("status")));
        return order;
    });

场景2:自定义数据库存储值(比如枚举有专属的db字段)

如果你的枚举有自定义的数据库存储值(比如不是用name(),而是单独定义的dbValue):

public enum OrderStatus {
    ACTIVE("active", "Active Order"),
    AWAITING("awaiting", "Awaiting Order");

    private final String dbValue;
    private final String displayName;

    OrderStatus(String dbValue, String displayName) {
        this.dbValue = dbValue;
        this.displayName = displayName;
    }

    public String getDbValue() {
        return dbValue;
    }

    // 提供从dbValue转回枚举的方法
    public static OrderStatus fromDbValue(String dbValue) {
        for (OrderStatus status : values()) {
            if (status.dbValue.equals(dbValue)) {
                return status;
            }
        }
        throw new IllegalArgumentException("Unknown status: " + dbValue);
    }
}

保存时传入自定义的dbValue:

params.addValue("orderStatus", orderStatus.getDbValue());

查询时用fromDbValue()转换:

order.setStatus(OrderStatus.fromDbValue(rs.getString("status")));

更优雅的方式:自定义类型转换器

如果不想每次都手动调用name()或getDbValue(),可以自定义一个类型转换器,注册到Spring的类型转换体系里:

import org.springframework.core.convert.converter.Converter;

public class OrderStatusToDbValueConverter implements Converter<OrderStatus, String> {
    @Override
    public String convert(OrderStatus source) {
        return source.getDbValue(); // 或者source.name()
    }
}

然后在配置类里注册这个转换器:

import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new OrderStatusToDbValueConverter());
    }
}

之后就可以直接把枚举对象传入MapSqlParameterSource,Spring会自动帮你转换:

params.addValue("orderStatus", orderStatus);

这样就彻底解决了枚举的持久化问题,也不会再碰到数据截断的异常啦!

内容的提问来源于stack exchange,提问作者Kathiresa J

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:46:56