データベースのバージョニング
ソースコード内のデータモデルがリレーショナルデータベースと確実に一致するようにするには、それらの同期を維持することが重要です。この課題に取り組むために一般的に使用される 2 つの方法があります。
データベースファースト
このアプローチでは、データベースは、「データベースリバースエンジニアリング」とも呼ばれるコード生成を通じてデータベーススキーマから生成されるデータモデルクラス (POJO または JPA エンティティ) よりも優先されます。生成されたクラスはいつでも再生成される可能性があり、ソースコードに加えられた変更は失われるため、生成されたクラスを変更しないようにすることが重要です。ただし、このアプローチでは、移行スクリプトの生成が不要になるわけではありません。これは、既存のインストールを最新バージョンにアップグレードするために必要なためです。
ソースコードファースト
これは逆のアプローチです。ここでは、データモデルクラスが唯一の真実のソースとして機能します。データベースはデータモデルに加えられた変更によって変更されます。データベースを更新するには、移行スクリプトで、古いデータベースの状態とデータモデルクラスの現在の状態の間の変更を、Flyway SQL 移行や Liquibase 変更ログなどの任意の形式で表す必要があります。
IntelliJ IDEA は、開発者がこれら 2 つのシナリオのそれぞれを進めるのに役立つ便利なツールを提供します。このガイドでは、IntelliJ IDEA が差分更新スクリプトの生成にかかる時間を大幅に節約する方法を説明します。
ライブラリサポート
IntelliJ IDEA は、JPA とともに Java アプリケーションでよく使用される 2 つの一般的なソリューションをサポートしています。
一般的な差分スクリプトの生成 Flow
このセクションでは、移行スクリプト生成の基本原則について説明します。Liquibase および Flyway で移行スクリプトを生成する方法の詳細については、Liquibase および Flyway を参照してください。
差分移行スクリプトを生成するには、データベースでデータベース接続を右クリックし、Liquibase 変更ログを作成するまたは Flyway バージョン移行の作成を選択します。ビルドファイルに JPA および Liquibase または Flyway 依存関係が追加されている場合、アクションは使用できます。
開いたダイアログで、ソース (データモデルの望ましい状態) とターゲット (データモデルの古い状態) を選択します。
結果の移行スクリプト = 現在の状態 (ソース) – 以前の状態 (ターゲット)。
IntelliJ IDEA は、ターゲットデータベースをソースの状態にアップグレードするための移行スクリプトを生成します。
次のソースオプションから選択できます。
DB — 最新のデータベースがあり、別の DB を同じ状態に更新するための移行スクリプトを生成したい場合に使用する必要があります。
モデル — エンティティ関係モデル (JPA エンティティ) の現在の状態と古い (ターゲット) 状態の違いを表す移行スクリプトを生成するために使用します。
ターゲットは次のように設定できます。
DB — ターゲット DB のスキーマが古いバージョンです。
スナップショット - 必要な状態がデータモデルのスナップショットに保存されている場合は、このオプションを使用します。これは JPA Buddy でも生成できます。
「OK」をクリックして次に進みます。JPA Buddy はソースとターゲットの違いを分析し、結果の移行スクリプトを微調整できるようにプレビューダイアログを表示します。「保存」をクリックして、新しいスクリプトをプロジェクトに追加するか、既存のスクリプトを追加します。
差分移行スクリプト生成オプション
データベースの使用
ソースデータベースがデータモデルとすでに同期されている場合、データベースを別のデータベース / スナップショットと比較することは理にかなっています。JPA エンティティに従ってデータベースを維持するには、次の 2 つの一般的なアプローチがあります。
スキーマ自動ジェネレーターの使用 (Hibernate および EclipseLink は独自の実装を提供します)。Hibernate のドキュメントでも、プロトタイピングやテストの目的を超えてこの方法を使用しないように警告していることに注意してください。
JPA エンティティの変更をデータベーススキーマに手動で適用します。このアプローチは、特にデータモデルが頻繁に変更される開発初期段階では、手間がかかりすぎるように見えるかもしれません。
データモデルの使用
アプリケーションは、JPA エンティティを使用して、JPA 原則に従って、エンティティ、関連付け、インデックス、その他の関連要素を含むデータモデルを表します。つまり、データベーススキーマに関する十分な情報がすでに含まれています。ソースコードが唯一の真実の点であり、最新の (ソース) スキーマを表します。このため、差分変更ログを生成するには、データモデルをデータベース / スナップショットと比較することが望ましいのです。
IntelliJ IDEA はすべての JPA オブジェクトをスキャンし、ターゲットデータベースまたはスナップショットと比較して、差分移行スクリプトを生成します。
データモデルが現在のスキーマ状態のソースとして機能する場合、永続性ユニットが選択されます。
ドキュメントに従って (英語) : 永続化ユニットは、アプリケーション内の EntityManager インスタンスによって管理されるすべてのエンティティクラスのセットを定義します。このエンティティクラスのセットは、単一のデータストア内に含まれるデータを表します。
つまり、アプリケーションが複数のデータストアを使用する場合、対応する永続性ユニットを指定して、それぞれに対して個別に移行スクリプトを生成する必要があります。
データモデルのスナップショットの使用
IntelliJ IDEA では、データモデルスナップショットを比較のターゲットとして使用できます。変更を以前のアプリケーションバージョンにマージする場合など、モデルの特定の状態のデータベースを取得することが不可能または困難な場合があります。リリースごとにデータベースダンプを保持するのは不可能な場合があります。IntelliJ IDEA を使用すると、必要なバージョンのアプリケーションをチェックアウトし、JPA エンティティに基づいて JSON スナップショットを生成できるため、差分移行スクリプトを作成するときにデータベースが不要になります。
データモデルスナップショットの生成
永続化ツールウィンドウを開きます。
要素を右クリックし、
を選択します。
![data-model-snapshot data-model-snapshot](https://resources.jetbrains.com/help/img/idea/2024.2/data-model-snapshot.png)
これにより、古い時点でのデータモデルの状態をキャプチャーできるため、その時点から現在までに発生したすべての変更を記述した差分移行スクリプトを作成できます。
例: フィーチャーブランチで作業しており、モデルを変更しました。マージする前に、このブランチのみの変更を説明する diff 変更ログを作成する必要があります。
設定によっては、メインのブランチと常に同期している DB がない場合があります。リリースブランチなど、メインのブランチ以外のアプリケーションの状態に変更をマージする必要がある場合、状況はさらに複雑になります。リリースごとにデータベースダンプを維持するのは現実的ではない可能性があります。IntelliJ IDEA は、よりシンプルな代替手段を提供します。
ターゲットブランチをチェックアウトします (たとえば、メインまたはリリース)
ブランチでモデルのスナップショットを作成します
機能をチェックアウトブランチ
モデルと手順 2 で作成したスナップショットを比較して、差分移行スクリプトを生成します。
4 つの簡単な手順で、現在のブランチとターゲットブランチの間の変更を記述した移行スクリプトを取得できます。
プレビューウィンドウ
Liquibase のプレビューウィンドウは次のようになります (Flyway のプレビューウィンドウは少し異なります)。
![changelog-preview changelog-preview](https://resources.jetbrains.com/help/img/idea/2024.2/changelog-preview.png)
一部の種類の変更には、プレビューウィンドウにカスタムフィールドがあります。例: not null 制約の変更を追加すると、 DB 内のすべての既存の NULL 値を指定した値に置き換えることができます。
![changelog-preview-update-null changelog-preview-update-null](https://resources.jetbrains.com/help/img/idea/2024.2/changelog-preview-update-null.jpeg)
各変更タイプは、その危険レベルに応じて色分けされています。緑色は安全、黄色は注意、赤色は危険です。SAFE 操作は、いかなる形でもデータの損失を引き起こすことがない操作です。たとえば、列を追加しても既存のデータには影響しません。「CAUTION」とマークされた操作は通常は安全ですが、注意が必要です。たとえば、列に NULL 値がある場合、非 null 制約の追加は失敗する可能性があります。危険な操作では、列の削除やデータ型の変更など、データの損失が発生する可能性があります。
危険レベルは、
の IDE 設定でカスタマイズできます。![diff-changes-preferences diff-changes-preferences](https://resources.jetbrains.com/help/img/idea/2024.2/diff-changes-preferences.png)
各変更タイプの場所をプライマリまたはセカンダリの場所に構成することも、完全に無視することもできます。デフォルトでは、新しく生成された移行スクリプトは無視された変更を除外しますが、それらの変更はプレビュー中に「無視」セクションに表示されるため、手動で追加し直すことができます。Liquibase の場合、各変更タイプに使用するコンテキストとラベルを設定することもできます。
ステートメントのマージ
基本的に、テーブル名、列名などのスキーマ要素の名前を変更すると、次の 2 つのステートメントが生成されます。
既存の値を削除する
新しいものを追加
しかし、JPA Buddy は、このようなステートメントを単一の名前変更ステートメントまたは変更ステートメントに置き換えることができます。例: 列 / テーブル / シーケンスの名前を変更したり、列の種類を変更したりすると、プレビューウィンドウに 2 つのステートメントが表示されます。ただし、関連するステートメントのいずれかを選択すると、結合できます。
マージ後は、drop ステートメントは無関係になる可能性があります。移行スクリプトから削除する変更を選択できます。例: ID 列の名前を変更した後 (古い値を削除して新しい値を追加するのではなく)、それに新しい主キーを追加する必要はありません。
![unnecessary-changes unnecessary-changes](https://resources.jetbrains.com/help/img/idea/2024.2/unnecessary-changes.jpeg)
エンティティ別の DDL
エンティティ別の DDL を生成アクションを使用すると、開発者は数回クリックするだけでエンティティを DDL ステートメントに変換できます。次のものを生成できます。
データベーススキーマを最初から作成するための初期化スクリプト。
既存のデータベースを JPA エンティティに従って有効な状態に更新する差分 DDL。
また、この機能は、hbm2ddl
または ddl-auto
プロパティによって有効になる自動スクリプト生成の使用を避けたい場合にも非常に便利です。JPA Buddy アクションを使用すると、実行前に DDL を完全に制御し、適切な Java -> DB タイプのマッピングを設定し、属性コンバーターと Hibernate タイプを使用してフィールドをマップし、ドロップステートメントを生成するなど、さまざまなことが可能になります。
SchemaManagementException を自動的に解決する
アプリケーションの起動時に SchemaManagementException
に遭遇した場合、ddl-auto
プロパティが validate
に設定されており、Hibernate が JPA エンティティをデータベーステーブルに適切にマップできなかったことを意味します。JPA Buddy を使用すると、スタックトレースから JPA エンティティとデータベースの差分を埋めるための DDL を生成できます。
DDL アクションを表示
JPA Buddy は、特定の 1 つのエンティティに対してのみ DDL ステートメントを生成するアクションを提供します。DDL を表示するには、クラス名の上にカーソルを置き、IntelliJ IDEA コンテキストアクションメニューまたは JPA インスペクターからアクションを呼び出します。また、プロジェクトパネルと JPA 構造タブからこのアクションを呼び出すこともできます。ターゲットエンティティを右クリックするだけです。
![show-ddl show-ddl](https://resources.jetbrains.com/help/img/idea/2024.2/show-ddl.png)
次に、どのデータベースに対してスクリプトが必要かを選択し、「OK」をクリックします。
![show-ddl-dbs show-ddl-dbs](https://resources.jetbrains.com/help/img/idea/2024.2/show-ddl-dbs.png)
![sql-preview sql-preview](https://resources.jetbrains.com/help/img/idea/2024.2/sql-preview.png)
SQL ビジュアルデザイナー
場合によっては、特に新しいデータベースを迅速にセットアップする必要がある場合に、JPA データモデル用の SQL スクリプトがあると便利です。JPA Buddy は、JPA パレットまたはエディターツールバーを介して幅広い SQL ステートメントを生成できます。各ステートメントには、ステートメントを構成できる対応するウィンドウがあります。
Hibernate 6 サポート
Hibernate 6 より前は、非標準 SQL 型を Java 型にマッピングするために、Hibernate タイプライブラリまたは @Type
/@Converter
アノテーションが一般的に使用されていました。Hibernate 6 では、マッピング用の新しいアノテーションが利用できるようになり、多数の Hibernate 型と JPA コンバーターが不要になりました。現在、JPA Buddy では次の新しいマッピングアノテーションがサポートされています。
@JdbcType
、@JdbcTypeCode
、@JdbcTypeRegistration
@Type
、@JavaType
、@JavaTypeRegistration
@TimeZoneStorage
&@TimeZoneColumn
Hibernate エンバースのサポート
Hibernate エンバース(英語)は、データベース内のエンティティ監査を容易にするモジュールです。JPA Buddy は、Hibernate Envers が正しく機能するために必要なすべてのテーブルを生成できます。これには、@Audited
アノテーションでマークされたエンティティの監査テーブルと、@RevisionEntity
アノテーションでアノテーションが付けられたエンティティのリビジョンテーブルが含まれます。実際にどのように動作するかを確認してください。
JPA Buddy は、Hibernate Envers の柔軟な設定を提供します。詳細については、該当するセクションを参照してください。
設定
カスタム型マッピング
カスタム Java タイプを SQL/Liquibase タイプに自動的にマップする一般的な方法はありません。そのため、これらの属性のターゲットタイプを手動で定義する必要があります。プロジェクトにこのような属性が存在する場合、Liquibase または Flyway スクリプト生成アクションが呼び出された後、JPA Buddy は次のウィンドウを表示します。
![undefined-mapping-detected undefined-mapping-detected](https://resources.jetbrains.com/help/img/idea/2024.2/undefined-mapping-detected.jpeg)
保存されたマッピング構成は、
からいつでも変更できます。また、アプリケーションがさまざまなベンダーのデータベースと連携する場合にも役立つ場合があります。この場合、スキーマのデータ型はそれぞれわずかに異なる可能性があります。
アプリケーションが PostgreSQL と MS SQL の両方をサポートする必要があるとします。そして、Unicode 文字を文字列に保存したいとします。PostgreSQL は VARCHAR
の Unicode 文字をサポートしますが、MS SQL にはそれ用の別の NVARCHAR
データ型があります。
各 DBMS の型マッピングを指定できます。JPA コンバーターと Hibernate 型のマッピングを設定することもできます。
![type-mappings type-mappings](https://resources.jetbrains.com/help/img/idea/2024.2/type-mappings.png)
コンバーター
型マッピングを簡素化するために、IntelliJ IDEA は DB に依存しない SQL 型を導入し、DB 固有の型に変換します。例: 「varchar」は Oracle DB では「varchar2」に変換され、PostgreSQL では「varchar」のままになります。
DB に依存しない各タイプには、一連のエイリアス (たとえば、「java.sql.Types.VARCHAR」または「character varying」) があり、ほとんどの場合は互換性があります。不明なタイプは、変換されずにそのまま使用されます。表のエイリアスの完全なリストを確認してください。
名前 | エイリアス | Liquibase クラス |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Hibernate エンバース
![hibernate-envers-settings hibernate-envers-settings](https://resources.jetbrains.com/help/img/idea/2024.2/hibernate-envers-settings.png)
Hibernate Envers はさまざまなカスタマイズオプションを提供します。JPA Buddy 設定 (2) で必要な構成を指定するか、JPA Buddy に .properties
ファイルから既存の設定を自動的に読み取らせることができます (1)。
命名戦略
デフォルトでは、Spring Boot は SpringPhysicalNamingStrategy
を使用して物理的な命名戦略を構成します。この実装では、すべてのテーブル名がアンダースコアで区切られた小文字で生成されます。例: TelephoneNumber
エンティティは telephone_number
テーブルにマップされます。エンティティに @Table(name = "TelephoneNumber")
でアノテーションを付ける場合でも、移行スクリプトでは同じ名前を使用する必要があります。そのため、JPA Buddy はスクリプト生成中にすべての名前に物理的な命名戦略も適用します。
次の戦略がサポートされています。
SpringPhysicalNamingStrategy
– デフォルトのオプションPhysicalNamingStrategyStandardlmpl
CamelCaseToUnderscoresNamingStrategy
(Hibernate 6 以降のバージョンのプロジェクトのみ)
命名戦略の詳細については、記事(英語)を参照してください。
カスタム命名戦略
場合によっては、プロジェクト内の命名戦略のデフォルトの動作が変更されることがあります。JPA Buddy もそれをお手伝いします。プロジェクト内で org.hibernate.boot.model.naming.PhysicalNamingStrategy
(またはその後継の 1 つ) を実装するクラスが検出されると、対応するクラスを含む追加の「カスタム」セクションが命名戦略ドロップダウンメニューに表示されます。
![custom-naming-strategy.png custom-naming-strategy.png](https://resources.jetbrains.com/help/img/idea/2024.2/custom-naming-strategy.png)
ドロップダウンメニューからこのクラスを選択すると、IntelliJ IDEA は移行スクリプトを生成するときにこの戦略を使用します。IntelliJ IDEA はクラスの変更を自動的に更新しないため、戦略コードを変更する場合は、カスタム物理命名戦略クラスを再ロードをクリックするか、IntelliJ IDEA を再起動する必要があります。
![reload-custom-naming-strategy.png reload-custom-naming-strategy.png](https://resources.jetbrains.com/help/img/idea/2024.2/reload-custom-naming-strategy.png)
最大識別子
RDBMS には独自の制限があります。例: 12.1 バージョンより前の OracleDatabase(英語) のテーブル名は 30 バイトに制限されています。バージョン管理スクリプトの問題を回避するために、テーブル名を制限できます。
![max-db-identifier max-db-identifier](https://resources.jetbrains.com/help/img/idea/2024.2/max-db-identifier.png)
また、次のように定義することもできます。
関連外部キー制約のインデックスを作成するかどうか。
主キー制約名。
関連ページ:
![](https://resources.jetbrains.com/help/img/idea/2024.2/db_connection_details_postgresql_default.png)
データベースへの接続
データベースツールと SQL プラグインを有効にするこの機能は、IntelliJ IDEA にデフォルトでバンドルされ有効になっているデータベースツールと SQL プラグインに依存しています。関連する機能が利用できない場合は、プラグインを無効にしていないことを確認してください。を押して設定を開き、を選択します。インストール済みタブを開き、データベースツールおよび SQL プラグインを見つけて、プラグイン名の横にあるチェックボックスを選択します。このトピックでは、IntelliJ IDEA でのデー...
![](https://resources.jetbrains.com/help/img/idea/2024.2/init-schema-changelog.jpeg)
Liquibase
対応する機能を有効にするには、プロジェクトに Liquibase 依存関係が含まれていることを確認してください。また、変更ログをすばやく生成して実行したり、SQL ステートメントをプレビューしたりするためのさまざまなアクションも提供されます。<dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> </dependen...
![](https://resources.jetbrains.com/help/img/idea/2024.2/diff-custom-scope.png)
Flyway
対応する機能を有効にするには、プロジェクトに Flyway 依存関係が含まれていることを確認してください。<dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency>dependencies { implementation 'org.flywaydb:flyway-core' }dependen...
![](https://resources.jetbrains.com/help/img/idea/2024.2/persistence_tool_window.png)
永続化ツールウィンドウ
プロジェクトに JPA ファセットを持つモジュールが少なくとも 1 つある場合は、永続化ツールウィンドウを使用できます。プロジェクトの依存関係に基づいて、次の要素が表示されます。JPA: JPA 項目 (構成ファイル、永続性ユニット、管理対象エンティティ (永続クラスとフィールド)、Spring リポジトリ、JPA コンバーター) を表示および管理します。Spring Data モンゴ DB: MongoDB クラスを表示し、MongoDB ドキュメントから新しいクラスとフィールドを生成します。L...
![](https://resources.jetbrains.com/help/img/idea/2024.2/install_plugin_from_disk.png)
JPA Buddy
JPA Buddy は、開発者が Hibernate、EclipseLink、Spring Data JPA、Flyway、Liquibase、Lombok、MapStruct、その他の関連テクノロジーを Java と Kotlin の両方で効率的に使用できる IntelliJ IDEA プラグインです。このプラグインは、JPA を使用した開発への参入障壁を下げ、開発者の生産性を向上させ、コードがベストプラクティスに従っていることを確認します。JPA Buddy は以下を提供します。JPA を操作...
![](https://resources.jetbrains.com/help/img/idea/2024.2/reverse%20engineering_create_entity_action.png)
リバースエンジニアリング
リバースエンジニアリングは、データベーススキーマに基づいて JPA エンティティクラスをスキャフォールディングするプロセスです。データベースから JPA エンティティを生成するデータベース接続が確立されていない場合は、接続を作成します。データベースツールウィンドウで、JPA ノードを展開し、データベースまたは特定のテーブルを右クリックして、を選択します。マップするデータベース接続、テーブル、属性を選択します。詳細については、DB ウィザードからのエンティティを参照してください。IDE が開いている...