如何在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
相关产品推荐
相关产品推荐

