PostgreSQL特有のデータ側をPythonから利用する方法について調べたので記録しておきます。
ここで紹介するのはjsonb型についてです。
この内容は、第51回 長岡IT開発者勉強会で発表した内容の抜粋です。スライドはこちらです。
Python版はこちらです。
PostgreSQLをJavaから利用する
アプリケーションからPostgreSQLを使用するときには、
JDBC API経由で使う。JDBC APIは仕様でインターフェースのみとなり実装としてJDBC Driver for PostgreSQLがある。これはPostgreSQL公式のJDBCドライバ。
JDBC経由で様々なDBアクセス用ライブラリが存在するが、今回はJava標準の永続化仕様としてJPAを使用する例を考える。JPAも仕様でありインターフェースが用意されてある。実装の一つとしてEclipseLinkがある。
ソースコード
https://github.com/civic/postgresql-java-json
jsonbを利用する
id | info |
---|---|
1 | {"a": 100, "b": "Hello"} |
2 | {"a": 200, "b": "World"} |
CREATE TABLE json_test(
id integer,
info jsonb
)
低レベルAPI(JDBC)からjsonbの利用
SELECT
resultSet.getString("info");
// {"a": 100, "b": "Hello"}
jsonの列を取得し、getStringすることでJSON文字列を取得可能。
INSERT (1)
import org.postgresql.util.PGobject;
PGobject pgobj =new PGobject();
pgobj.setValue(json_string); //json文字列
pgobj.setType("jsonb");
preparedStatement.setObject(1, pgobj);
JDBC APIにはJSON型はない。JDBCの提供するインターフェース経由で使うのが普通だが、PostgreSQL提供のドライバの機能を使うしかない。共通ライブラリなど限定された箇所で使うべき。
INSERT (2)
PreparedStatement ps =conn.prepareStatement(
"INSERT INTO json_test(info) VALUES(jsonb(?))"
);
ps.setString(1, json_string); //json文字列
JSON文字列としてパラメータをセットし、SQL文でjsonbにキャストするパターン。
文字列としてsetStringするので、標準APIのみで可能。
高レベルAPI(JPA)からjsonbの利用
SELECT / INSERT
@Entity
@Table(name = "json_test")
public class JsonTest implements Serializable {
// ... 中略 ...
@Column(name = "info")
@Convert(converter = JsonbConverter.class)
private String info;
...
JPAというORマッパー的な永続化機能。JPAの仕様でConverterという仕組みが用意されている。
Converterを作成し、Java型 <=> SQL型の相互変換を定義すれば、アノテーションで列定義に使用できる。
JsonbConverterの実装
/**
@Converter
public class JsonbConverter implements AttributeConverter<String, PGobject>{
/**
* String-Pgobjectへの変換
* @param x
* @return
*/
@Override
public PGobject convertToDatabaseColumn(String x) {
PGobject pgobject =new PGobject();
pgobject.setType("jsonb");
try {
pgobject.setValue(x);
} catch (SQLException ex) {
Logger.getLogger(JsonbConverter.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
return pgobject;
}
@Override
/**
* Pgobject-Stringへの変換
* @param y
* @return
*/
public String convertToEntityAttribute(PGobject y) {
return y.getValue();
}
}