🐧

MyBatisでPostgreSQLのJSONデータ型を利用する

2023/06/30に公開

PostgreSQLには、JSONを格納するためのデータ型があります。

使う頻度は少ないかもしれない(私も10数年PostgreSQL使ってきて、片手で数えられるくらいしかカラムとして使ったこと無い)ですが、下記の両方を満たすような場合には有用なデータ型だと思っています。

  • プログラムで利用しているデータオブジェクトをそのままDBに保存しておきたい
    • 特にテーブルとして定義するのが面倒な形式なとき
  • SQLでオブジェクトの中を参照するようなことがない

Spring Boot + MyBatis を利用して、PostgreSQLのJSONデータ型(jsonb)へのマッピング方法を書いていきます。
確認した際の各バージョンは下記の通りです。

  • PostgreSQL 15.3
  • Java 17
  • Spring Boot 3.1.0
  • MyBatis 3.5.13

テーブル定義

今回は下記のようなテーブルを定義します。

CREATE TABLE json_records (
  id serial,
  json jsonb
);

jsonという名前のカラムが、JSONを格納するためのカラムになります。jsonb型のカラムです。

エンティティ

テーブルにあわせて、下記のようなエンティティクラスを定義します。

package com.github.onozaty.mybatis.pg.example.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class JsonRecord {
    private int id;
    private JsonData json;
}

JsonDataがJSONとして格納したいオブジェクトです。

package com.github.onozaty.mybatis.pg.example.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class JsonData {
    private int id;
    private String name;
    private List<Integer> nums;
}

リポジトリ

リポジトリです。
JSONだからといって、特別な書き方はしません。

package com.github.onozaty.mybatis.pg.example.repository;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.github.onozaty.mybatis.pg.example.domain.JsonRecord;

@Mapper
public interface JsonRepository {

    @Select("""
INSERT INTO json_records (
  json
)
VALUES (
  #{json}
)
RETURNING *
    """)
    JsonRecord insert(JsonRecord record);

    @Select("""
SELECT * FROM json_records
    """)
    List<JsonRecord> selectAll();

    @Select("""
SELECT * FROM json_records WHERE id = #{id}
    """)
    JsonRecord select(int id);

    @Update("""
UPDATE json_records
SET
  json = #{json}
WHERE
  id = #{id}
    """)
    void update(JsonRecord record);
}

JSON用のTypeHandlerの設定

MyBatisの標準の機能ではPostgreSQLのJSON用のTypeHandlerは無いので、下記のライブラリを利用します。

依存関係を追加します。(Gradleを利用しているのでbuild.gradleに追加)

    implementation 'com.github.onozaty:mybatis-postgresql-typehandlers:1.0.2'

JSONとして保存するオブジェクトのTypeHandlerをcom.github.onozaty.mybatis.pg.type.json.JsonTypeHandlerにするのですが、Spring Bootのapplication.propertiesでは書けないので、ConfigurationCustomizerを利用して設定します。

package com.github.onozaty.mybatis.pg.example;

import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.github.onozaty.mybatis.pg.example.domain.JsonData;
import com.github.onozaty.mybatis.pg.type.json.JsonTypeHandler;

@Configuration
public class MyBatisConfiguration {

    @Bean
    public ConfigurationCustomizer mybatisConfigurationCustomizer() {
        return (configuration) -> {
            configuration.getTypeHandlerRegistry().register(JsonData.class, JsonTypeHandler.class);
        };
    }
}

これでJSONとしてPostgreSQLに保存/PostgreSQLから取得できるようになります。

コード全体

コード全体は下記プロジェクトになります。
JSON以外にもJavaのenumとPostgreSQLのenum、JavaのListとPostgreSQLのARRAYをマッピングするためのコードが含まれています。

参考

Discussion