Spring Boot R2DBC操作PostgreSQL枚举触发BadSqlGrammarException错误
解决Spring Boot R2DBC + PostgreSQL枚举类型更新错误问题
核心问题原因
调用save方法更新实体时,尽管你只修改了updatedAt字段,但Spring Data R2DBC会生成全字段更新语句。此时实体中的枚举字段被序列化为普通字符串,而PostgreSQL期望接收的是自定义ENUM类型(如chat_room_type),导致类型不匹配错误:column "type" is of type chat_room_type but expression is of type character varying。
解决方案
方案1:正确配置EnumCodec(推荐)
Spring Data R2DBC的EnumCodec需要直接注册到PostgreSQL R2DBC驱动的CodecRegistry中,原配置方式未生效。修改配置类:
@Configuration public class R2dbcConfig { @Bean public ConnectionFactoryCustomizer connectionFactoryCustomizer() { return connectionFactory -> { if (connectionFactory instanceof PostgresqlConnectionFactory) { ((PostgresqlConnectionFactory) connectionFactory).getConfiguration().codecRegistrar( EnumCodec.builder() .withEnum("chat_room_type", ChatRoomType.class) .withEnum("chat_room_visibility", ChatRoomVisibility.class) .withEnum("chat_room_member_role", ChatRoomMemberRole.class) .withEnum("notification_preference", NotificationPreference.class) .withEnum("gender", Gender.class) .build() ); } }; } }
说明:该配置直接将EnumCodec注入PostgreSQL连接工厂,驱动会自动把Java Enum映射到对应PostgreSQL自定义ENUM类型,无需额外转换器。
方案2:修正自定义转换器(若坚持使用转换器)
原转换器将Enum转为字符串,不符合数据库类型要求,需改为转换为PostgreSQL专用的PgEnum类型:
- 确保依赖完整(若未添加):
<!-- Maven --> <dependency> <groupId>io.r2dbc</groupId> <artifactId>r2dbc-postgresql</artifactId> </dependency>
- 修改转换器实现:
@WritingConverter public class ChatRoomTypeWritingConverter implements Converter<ChatRoomType, PgEnum> { @Override public PgEnum convert(ChatRoomType source) { return () -> "chat_room_type"; // 指定PostgreSQL中对应的ENUM类型名称 } } @ReadingConverter public class ChatRoomTypeReadingConverter implements Converter<PgEnum, ChatRoomType> { @Override public ChatRoomType convert(PgEnum source) { return ChatRoomType.valueOf(source.getValue().toUpperCase()); } }
- 正确注册转换器:
@Configuration @EnableR2dbcRepositories public class R2dbcConfig extends AbstractR2dbcConfiguration { @Override protected List<Object> getCustomConverters() { List<Object> converters = new ArrayList<>(); // 添加所有枚举类型的转换器 converters.add(new ChatRoomTypeReadingConverter()); converters.add(new ChatRoomTypeWritingConverter()); converters.add(new ChatRoomVisibilityReadingConverter()); converters.add(new ChatRoomVisibilityWritingConverter()); converters.add(new ChatRoomMemberRoleReadingConverter()); converters.add(new ChatRoomMemberRoleWritingConverter()); return converters; } @Override public ConnectionFactory connectionFactory() { // 配置你的PostgreSQL连接信息 return PostgresqlConnectionFactory.builder() .host("localhost") .database("your_database") .username("your_username") .password("your_password") .build(); } }
说明:继承AbstractR2dbcConfiguration可确保转换器被Spring Data R2DBC正确识别,PgEnum类型能被驱动解析为PostgreSQL的ENUM类型。
额外检查点
- 实体类字段配置:确保枚举字段未错误标注为字符串类型,可显式指定数据库类型:
public class ChatRoom { // 其他字段... @Column(columnDefinition = "chat_room_type") private ChatRoomType type; // 其他字段... }
- 避免配置冲突:EnumCodec和自定义转换器二选一,不要同时使用,否则会导致类型转换逻辑冲突。
- 验证SQL生成:观察错误日志中的UPDATE语句,确认枚举字段参数已被正确转换为PostgreSQL ENUM类型,而非字符串。
内容的提问来源于stack exchange,提问作者check
相关产品推荐
相关产品推荐

