PostgreSQLのEnumとSpringDataJPAの結合

PostgreSQLのEnumとSpringDataJPAの結合

카테고리
Springboot
태그
Spring Data JPA
PostgreSQL
Java
本投稿ではHibernate6 & PostgreSQL10以上の場合を説明します。
 
SpringbootでJPAを利用してデータベースにあるデータを保存する時にはJavaのEntityクラスにいろんなタイプを定義します。(String、Integer、Bigdecimalなと) そしてJAVAのEnumでタイプを定義することはとても一般的なことだと思います。
もし、PostgreSQLデータベースにEnumタイプを保存する時、Integerとして保存していませんか? そうであれば、ぜひこの記事をお読みください。
 

JavaのEnumをIntegerで保存

簡単な注文を保存するテーブルがあると仮定し、Springbootクラスを作成します。
@Entity public class Orders { @Id private String id; private OrderStatus status; }
public enum OrderStatus { PENDING, CONFIRMED, CANCELLED }
 
OrdersテーブルのDDLを作成します。
CREATE TABLE orders ( id VARCHAR PRIMARY KEY, status INTEGER NOT NULL );
上記のテーブルにデータを保存すると以下のデータが保存されます。
notion image
Integerを使用する時はデータベースの内容だけでは各ステータスの意味を理解することができません。
もし、この状態でステータスが「PENDING」のデータを検索するクエリを作成するとしても
SELECT * FROM orders WHERE status = 0;
上記のようにマジックナンバーがクエリに含まれることになります。今の問題点を少し直してみましょう。
 

JavaのEnumをVARCHARで保存

Integerで保存する時の問題を解決するため、コードを少し修正します。
@Entity public class Orders { @Id private String id; @Enumerated(EnumType.STRING) // ENUMタイプを文字列でマッピ private OrderStatus status; }
CREATE TABLE orders ( id VARCHAR PRIMARY KEY, status VARCHAR NOT NULL );
修正後、もう一度データを保存します。
notion image
今はデータベースの内容だけでも各ステータスの意味を理解することができます。
クエリを見ても条件の意味が伝わることになりました。
SELECT * FROM orders WHERE status = 'PENDING';
でも、文字列だけではまだ問題点は存在します。
例えば、「CONFIRMED」を「COMPLETED」に変更したい場合はどうでしょうか。
UPDATE orders SET status = 'COMPLETED' WHERE status = 'CONFIRMED'
今の例ではOrdersテーブルだけ「CONFIRMED」を「COMPLETED」に更新するクエリを実行することだけですが、実際は複数のテーブルが関わることが一般的です。
 

JavaのEnumをカスタムタイプで保存

Integer、VARCHARで保存する時の問題を解決するため、コードを少し修正します。
@Entity public class Orders { @Id private String id; @Enumerated(EnumType.STRING) // ENUMタイプを文字列でマッピング @JdbcType(PostgreSQLEnumJdbcType.class) // PostgresのENUMタイプを使用 private OrderStatus status; }
CREATE TYPE ORDER_STATUS AS ENUM ('PENDING', 'CONFIRMED', 'CANCELLED'); -- PostgreSQLタイプ定義 CREATE TABLE orders ( id VARCHAR PRIMARY KEY, status ORDER_STATUS NOT NULL -- PostgreSQLカスタムタイプ使用 );
修正後、もう一度データを保存します。
notion image
文字列として保存することと違いはありません。 でも、「CONFIRMED」を「COMPLETED」に変更する時は?
ALTER TYPE ORDER_STATUS RENAME VALUE 'CONFIRMED' TO 'COMPLETED';
上記のDDLを実行することでカラムの内容も変更されます。
notion image
そしてタイプを定義し保存すると検索時の利点もあります。タイピングミスがある場合、検索されずエラーになります。
notion image
カスタムタイプを利用する場合、他のデータベースに移行することが難しくなる可能性がありますので、注意する必要があります。
 

まとめ

Integer
String
Enum
意味の明確さ
数字のみでは不明確
意味が明確
意味が明確
データ制約
制約なし
制約なし
可能な値を指定
他のデータベースに移行
簡単
簡単
難しい
Integer、String、Enumタイプを比較して長短を調べました。
各プロジェクトを進めるにあたり、プロジェクトに適した仕様を決定する際の参考になれば幸いです。
 
最後までお読みいただき、ありがとうございました。
ご質問についてはなんでもいいので下記のメールでお問い合わせください。