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

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类型:

  1. 确保依赖完整(若未添加):
<!-- Maven -->
<dependency>
    <groupId>io.r2dbc</groupId>
    <artifactId>r2dbc-postgresql</artifactId>
</dependency>
  1. 修改转换器实现:
@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());
    }
}
  1. 正确注册转换器:
@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类型。


额外检查点

  1. 实体类字段配置:确保枚举字段未错误标注为字符串类型,可显式指定数据库类型:
public class ChatRoom {
    // 其他字段...
    @Column(columnDefinition = "chat_room_type")
    private ChatRoomType type;
    // 其他字段...
}
  1. 避免配置冲突:EnumCodec和自定义转换器二选一,不要同时使用,否则会导致类型转换逻辑冲突。
  2. 验证SQL生成:观察错误日志中的UPDATE语句,确认枚举字段参数已被正确转换为PostgreSQL ENUM类型,而非字符串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 16:10:55