如何在JDBI批量插入时将对象转JSON存入PostgreSQL的jsonb字段?
解决JDBI批量插入包含JSONB字段的Bean的问题
你的场景很常见——JDBI默认没法自动把自定义对象(比如SomeNameObject)映射到PostgreSQL的jsonb类型,所以需要我们告诉它怎么完成这个序列化转换。下面是几个靠谱的解决方案:
方案1:使用JDBI的Jackson插件(最省心)
如果你项目里已经用了Jackson做JSON序列化,直接用JDBI官方的Jackson扩展就能搞定,不用自己写绑定逻辑。
步骤:
- 首先添加依赖(Maven为例):
<dependency> <groupId>org.jdbi</groupId> <artifactId>jdbi3-jackson</artifactId> <version>你的JDBI版本</version> </dependency>
- 注册Jackson插件到你的JDBI实例:
Jdbi jdbi = Jdbi.create(dataSource); jdbi.installPlugin(new JacksonPlugin());
- 接下来修改你的
SomeObject?不用!只要SomeNameObject是普通POJO(有标准的构造方法、getter/setter),Jackson就能自动序列化它。你原来的批量插入代码完全不用改,JDBI会自动把SomeNameObject转成JSON字符串,再绑定到jsonb列上。
方案2:自定义绑定注解(灵活可控)
如果不想用插件,或者需要自定义序列化逻辑(比如指定日期格式、忽略某些字段),可以自己写一个绑定器来处理对象到JSONB的转换。
步骤:
- 定义一个自定义绑定注解:
@BindingAnnotation(BindJson.BinderFactory.class) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER, ElementType.FIELD}) public @interface BindJson { class BinderFactory implements BinderFactory { // 可以在这里配置自定义的ObjectMapper private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); @Override public Binder<BindJson, Object> build(BindJson annotation) { return (q, bind, value) -> { try { String json = OBJECT_MAPPER.writeValueAsString(value); // 用PGobject包装,明确告诉PostgreSQL这是jsonb类型 PGobject pgObject = new PGobject(); pgObject.setType("jsonb"); pgObject.setValue(json); q.bind(bind, pgObject); } catch (JsonProcessingException | SQLException e) { throw new RuntimeException("序列化对象到JSONB失败", e); } }; } } }
- 两种使用方式:
- 方式一:给
SomeObject的name字段加注解,保留原@BindBean用法:
这时原来的批量插入代码完全不用改,JDBI会自动用你的自定义绑定器处理public class SomeObject { String id; @BindJson SomeNameObject name; // 构造方法、getter/setter }name字段。 - 方式二:手动拆分参数绑定,适合更灵活的场景:
@SqlBatch("INSERT INTO something (id, name) VALUES (:id, :name)") void batchUpdate( @Bind("id") List<String> ids, @BindJson("name") List<SomeNameObject> names );
- 方式一:给
方案3:手动序列化(快速临时方案)
如果只是临时需求,不想改太多代码,可以在SomeObject里手动把name序列化成字符串,然后在SQL里转换为jsonb:
- 修改
SomeObject,新增一个返回JSON字符串的方法:
public class SomeObject { String id; SomeNameObject name; public String getNameAsJson() throws JsonProcessingException { return new ObjectMapper().writeValueAsString(name); } // 构造方法、getter/setter }
- 修改SQL语句,把字符串转成
jsonb:
@SqlBatch("INSERT INTO something (id, name) VALUES (:id, :nameAsJson::jsonb)") void batchUpdate(@BindBean List<SomeObject> someObjectList);
这个方法简单但不够优雅,适合临时场景,长期用还是推荐前两种方案。
内容的提问来源于stack exchange,提问作者Christian Kellner
相关产品推荐
相关产品推荐

