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

如何在PostgreSQL的JSONB列中存储Java对象(R2DBC)

如何用R2DBC将Java对象存储到PostgreSQL的JSONB列中

针对你给出的ScoringModel实体类,要把response字段存为PostgreSQL的JSONB类型,需要做几个关键配置,我一步步给你讲:

1. 先确认依赖是否齐全

首先确保你的项目里有这些必要依赖(以Maven为例):

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-r2dbc</artifactId>
</dependency>
<dependency>
    <groupId>io.r2dbc</groupId>
    <artifactId>r2dbc-postgresql</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

这些依赖分别提供R2DBC的Spring集成、PostgreSQL的R2DBC驱动,以及JSON序列化/反序列化的工具。

2. 修改实体类字段配置

你的response字段当前是Object类型,需要给它指定列类型为jsonb,并绑定自定义转换器来处理Java对象和JSONB的转换。修改后的实体类代码:

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Table("scoring")
public class ScoringModel extends BaseModel {

    @Column("client_id")
    @SerializedName(value = "clientId", alternate = {"client_id"})
    private String clientId;

    @Column("languages")
    @SerializedName(value = "languages", alternate = {"languages"})
    private String languages;

    // 明确指定列类型为jsonb,并绑定转换器
    @Column(value = "response", columnDefinition = "jsonb")
    @SerializedName(value = "response", alternate = {"response"})
    @Convert(converter = ObjectToJsonbConverter.class)
    private Object response; // 这里更推荐用Map<String, Object>或者自定义POJO,类型更安全
}

小提示:尽量不要用Object作为字段类型,换成Map<String, Object>或者你自己定义的响应DTO类,能避免很多类型转换的坑。

3. 实现自定义类型转换器

R2DBC不会自动把Java对象转成JSONB,所以需要写两个转换器:一个负责把Java对象序列化成JSON(写入数据库),另一个负责把JSONB反序列化成Java对象(读取数据库)。

写入转换器(Object → JSONB)

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.r2dbc.postgresql.codec.Json;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;

@WritingConverter
public class ObjectToJsonbConverter implements Converter<Object, Json> {

    private final ObjectMapper objectMapper;

    // 注入Spring容器中的ObjectMapper实例
    public ObjectToJsonbConverter(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public Json convert(Object source) {
        try {
            // 把对象序列化成JSON字符串,再转成PostgreSQL的Json类型
            String jsonString = objectMapper.writeValueAsString(source);
            return Json.of(jsonString);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("序列化对象到JSON失败", e);
        }
    }
}

读取转换器(JSONB → Object)

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.r2dbc.postgresql.codec.Json;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;

@ReadingConverter
public class JsonbToObjectConverter implements Converter<Json, Object> {

    private final ObjectMapper objectMapper;

    public JsonbToObjectConverter(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public Object convert(Json source) {
        try {
            // 把PostgreSQL的Json对象反序列化成Java对象
            return objectMapper.readValue(source.asString(), Object.class);
            // 如果是转成Map,就换成:
            // return objectMapper.readValue(source.asString(), new TypeReference<Map<String, Object>>() {});
        } catch (JsonProcessingException e) {
            throw new RuntimeException("从JSON反序列化对象失败", e);
        }
    }
}

4. 注册转换器到Spring容器

需要把这两个转换器配置到R2DBC的自定义转换体系中,创建一个配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions;
import org.springframework.data.r2dbc.dialect.PostgresDialect;

import java.util.Arrays;

@Configuration
public class R2dbcConfig {

    @Bean
    public R2dbcCustomConversions r2dbcCustomConversions(ObjectMapper objectMapper) {
        return R2dbcCustomConversions.of(PostgresDialect.INSTANCE,
                Arrays.asList(
                        new ObjectToJsonbConverter(objectMapper),
                        new JsonbToObjectConverter(objectMapper)
                ));
    }
}

5. 仓库层的使用

你的仓库接口只需要继承R2dbcRepository即可,不需要额外的方法:

import org.springframework.data.r2dbc.repository.R2dbcRepository;

public interface ScoringRepository extends R2dbcRepository<ScoringModel, Long> {
}

在服务层使用的时候,直接save对象就行,比如:

import reactor.core.publisher.Mono;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;

@Service
public class ScoringService {

    private final ScoringRepository scoringRepository;

    public ScoringService(ScoringRepository scoringRepository) {
        this.scoringRepository = scoringRepository;
    }

    public Mono<ScoringModel> saveScoringData() {
        ScoringModel model = new ScoringModel();
        model.setClientId("client_001");
        model.setLanguages("zh-CN,en-US");
        
        // 这里可以传入Map或者自定义POJO
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("totalScore", 85);
        responseData.put("evaluation", Map.of("quality", "good", "speed", "fast"));
        model.setResponse(responseData);
        
        return scoringRepository.save(model);
    }
}

一些额外建议

  • 尽量使用具体的类型代替Object,比如自定义ResponseDto类,这样转换器可以更精准地处理,避免类型转换异常。
  • 确保你的PostgreSQL表中response列的类型确实是jsonb,可以用SQL语句创建或修改:ALTER TABLE scoring ALTER COLUMN response TYPE jsonb;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:10:27