Spring WebFlux与R2DBC:枚举存MySQL TinyInt及序列化字符串异常解决
解决Spring WebFlux + R2DBC枚举字段tinyint存储与JSON字符串返回问题
问题分析
插入报错的核心原因是:R2DBC默认将枚举的名称字符串(如PENDING)传递给MySQL的tinyint字段,类型不匹配导致数据库抛出异常。需要同时处理两个关键环节:
- R2DBC与数据库交互时:实现枚举 ↔ tinyint 的双向类型转换
- API返回JSON时:将枚举序列化为对应的名称字符串
解决方案
1. 自定义R2DBC枚举转换器
通过实现读写转换器,让R2DBC正确处理枚举与tinyint的映射逻辑:
写入转换器(枚举转tinyint)
负责将枚举对象转换为数据库需要的整数类型:
import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.WritingConverter; @WritingConverter public enum StatusEnumWriteConverter implements Converter<StatusEnum, Integer> { INSTANCE; @Override public Integer convert(StatusEnum source) { return source.value; } }
读取转换器(tinyint转枚举)
负责将数据库返回的整数转换为对应的枚举实例:
import io.r2dbc.spi.Row; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.ReadingConverter; @ReadingConverter public enum StatusEnumReadConverter implements Converter<Row, StatusEnum> { INSTANCE; @Override public StatusEnum convert(Row source) { Integer statusValue = source.get("status", Integer.class); for (StatusEnum status : StatusEnum.values()) { if (status.value == statusValue) { return status; } } return StatusEnum.UNKNOWN; // 匹配不到时返回默认枚举值 } }
注册转换器到R2DBC配置
将自定义转换器注入R2DBC的转换体系:
import org.springframework.context.annotation.Configuration; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; import java.util.Arrays; @Configuration public class R2dbcConfig extends AbstractR2dbcConfiguration { // 若需自定义数据库连接工厂,可重写connectionFactory方法(根据自身数据源配置调整) @Override protected R2dbcCustomConversions r2dbcCustomConversions() { return new R2dbcCustomConversions( Arrays.asList( StatusEnumWriteConverter.INSTANCE, StatusEnumReadConverter.INSTANCE ) ); } }
2. 配置Jackson序列化枚举为字符串名称
有两种方式实现API返回时枚举序列化为名称字符串:
方式一:枚举类添加@JsonValue注解(推荐)
直接在枚举中定义序列化时返回的名称,同时支持前端传入字符串反序列化为枚举:
import com.fasterxml.jackson.annotation.JsonValue; import lombok.AllArgsConstructor; @AllArgsConstructor public enum StatusEnum { PENDING(11), IN_PROGRESS(12), SUCCESSFUL(13), FAILED(14), UNKNOWN(255); final int value; @JsonValue public String getStatusName() { return this.name(); } }
方式二:全局WebFlux Jackson配置
若需全局统一处理枚举序列化逻辑,可配置WebFlux的JSON编解码器:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.EnumSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.web.reactive.config.WebFluxConfigurer; @Configuration public class WebFluxConfig implements WebFluxConfigurer { @Bean public Jackson2JsonEncoder jackson2JsonEncoder() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(StatusEnum.class, new EnumSerializer(EnumSerializer.Feature.WRITE_ENUMS_USING_NAME)); mapper.registerModule(module); return new Jackson2JsonEncoder(mapper); } @Bean public Jackson2JsonDecoder jackson2JsonDecoder() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(StatusEnum.class, new EnumSerializer(EnumSerializer.Feature.WRITE_ENUMS_USING_NAME)); mapper.registerModule(module); return new Jackson2JsonDecoder(mapper); } }
验证效果
- 插入数据:R2DBC会自动将
StatusEnum.PENDING转换为11存入tinyint字段 - 查询数据:数据库返回的
tinyint值会转换为对应的枚举实例 - API返回:枚举会序列化为名称字符串,完全符合期望格式:
[ { "id": 1, "status": "PENDING" }, { "id": 2, "status": "IN_PROGRESS" }, { "id": 3, "status": "SUCCESSFUL" }, { "id": 4, "status": "FAILED" } ]
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

