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

如何在JDBI批量插入时将对象转JSON存入PostgreSQL的jsonb字段?

解决JDBI批量插入包含JSONB字段的Bean的问题

你的场景很常见——JDBI默认没法自动把自定义对象(比如SomeNameObject)映射到PostgreSQL的jsonb类型,所以需要我们告诉它怎么完成这个序列化转换。下面是几个靠谱的解决方案:

方案1:使用JDBI的Jackson插件(最省心)

如果你项目里已经用了Jackson做JSON序列化,直接用JDBI官方的Jackson扩展就能搞定,不用自己写绑定逻辑。

步骤:

  1. 首先添加依赖(Maven为例):
<dependency>
    <groupId>org.jdbi</groupId>
    <artifactId>jdbi3-jackson</artifactId>
    <version>你的JDBI版本</version>
</dependency>
  1. 注册Jackson插件到你的JDBI实例:
Jdbi jdbi = Jdbi.create(dataSource);
jdbi.installPlugin(new JacksonPlugin());
  1. 接下来修改你的SomeObject?不用!只要SomeNameObject是普通POJO(有标准的构造方法、getter/setter),Jackson就能自动序列化它。你原来的批量插入代码完全不用改,JDBI会自动把SomeNameObject转成JSON字符串,再绑定到jsonb列上。

方案2:自定义绑定注解(灵活可控)

如果不想用插件,或者需要自定义序列化逻辑(比如指定日期格式、忽略某些字段),可以自己写一个绑定器来处理对象到JSONB的转换。

步骤:

  1. 定义一个自定义绑定注解:
@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);
                }
            };
        }
    }
}
  1. 两种使用方式:
    • 方式一:给SomeObject的name字段加注解,保留原@BindBean用法:
      public class SomeObject {
          String id;
          @BindJson
          SomeNameObject name;
          // 构造方法、getter/setter
      }
      
      这时原来的批量插入代码完全不用改,JDBI会自动用你的自定义绑定器处理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:

  1. 修改SomeObject,新增一个返回JSON字符串的方法:
public class SomeObject {
    String id;
    SomeNameObject name;

    public String getNameAsJson() throws JsonProcessingException {
        return new ObjectMapper().writeValueAsString(name);
    }
    // 构造方法、getter/setter
}
  1. 修改SQL语句,把字符串转成jsonb:
@SqlBatch("INSERT INTO something (id, name) VALUES (:id, :nameAsJson::jsonb)")
void batchUpdate(@BindBean List<SomeObject> someObjectList);

这个方法简单但不够优雅,适合临时场景,长期用还是推荐前两种方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:30:00