MyBatisでPostgreSQLのJSONデータ型を利用する
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