Javaにはtransient
キーワードがあります。なぜ JPA は@Transient
既存の java キーワードを単に使用する代わりに持っているのですか?
8 に答える
Java のtransient
キーワードは、フィールドがシリアライズされないことを示すために使用されますが、JPA の@Transient
アノテーションは、フィールドがデータベースに永続化されないことを示すために使用されます。つまり、それらのセマンティクスは異なります。
意味が違うからです。@Transient
アノテーションは、JPA プロバイダーに (非transient
) 属性を保持しないように指示します。もう 1 つは、属性をシリアル化しないようにシリアル化フレームワークに指示します。@Transient
プロパティを持っていても、それをシリアル化したい場合があります。
他の人が言ったように、@Transient
永続化してはならないフィールドをマークするために使用されます。次の短い例を考えてみましょう。
public enum Gender { MALE, FEMALE, UNKNOWN }
@Entity
public Person {
private Gender g;
private long id;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public Gender getGender() { return g; }
public void setGender(Gender g) { this.g = g; }
@Transient
public boolean isMale() {
return Gender.MALE.equals(g);
}
@Transient
public boolean isFemale() {
return Gender.FEMALE.equals(g);
}
}
このクラスが JPA に供給されると、gender
andは永続化id
されますが、ヘルパーのブール メソッドを永続化しようとはしません@Transient
。基盤となるシステムがなければ、エンティティ クラスとメソッドPerson
が見つからないため、まったく永続化されないと文句を言うでしょう。setMale()
setFemale()
Person
目的が異なります:
transient
キーワードと@Transient
注釈には 2 つの異なる目的があります。1 つはシリアライゼーションを扱い、もう 1 つは永続性を扱います。プログラマーとして、私たちはしばしばこれら 2 つの概念を 1 つに結び付けますが、これは一般的に正確ではありません。永続性とは、状態を作成したプロセスよりも長く存続する状態の特性を指します。Java でのシリアル化とは、オブジェクトの状態をバイト ストリームとしてエンコード/デコードするプロセスを指します。
transient
キーワードは、より強い条件です@Transient
:
フィールドがキーワードを使用するtransient
場合、オブジェクトがバイト ストリームに変換されるときに、そのフィールドはシリアル化されません。さらに、JPA はtransient
キーワードでマークされ@Transient
たフィールドをアノテーションを持つものとして扱うため、フィールドも JPA によって永続化されません。
一方、@Transient
単独でアノテーションが付けられたフィールドは、オブジェクトがシリアル化されるときにバイト ストリームに変換されますが、JPA によって永続化されません。したがって、キーワードは注釈transient
よりも強い条件です。@Transient
例
ここで疑問が生じます: アプリケーションのデータベースに永続化されていないフィールドをシリアル化する必要があるのはなぜでしょうか? 実際には、シリアライゼーションは永続化以上の目的で使用されます。Enterprise Java アプリケーションでは、分散コンポーネント間でオブジェクトを交換するメカニズムが必要です。シリアル化は、これを処理するための共通の通信プロトコルを提供します。したがって、フィールドは、コンポーネント間通信の目的で重要な情報を保持できます。しかし、永続性の観点からは、同じフィールドに値がない場合があります。
たとえば、最適化アルゴリズムがサーバーで実行され、このアルゴリズムが完了するまでに数時間かかるとします。クライアントにとって、最新のソリューション セットを持つことは重要です。したがって、クライアントはサーバーにサブスクライブし、アルゴリズムの実行フェーズ中に定期的な更新を受け取ることができます。これらの更新は、ProgressReport
オブジェクトを使用して提供されます。
@Entity
public class ProgressReport implements Serializable{
private static final long serialVersionUID = 1L;
@Transient
long estimatedMinutesRemaining;
String statusMessage;
Solution currentBestSolution;
}
クラスは次のSolution
ようになります。
@Entity
public class Solution implements Serializable{
private static final long serialVersionUID = 1L;
double[][] dataArray;
Properties properties;
}
ProgressReport
サーバーはそれぞれをそのデータベースに永続化します。サーバーは永続化を気にしませんestimatedMinutesRemaining
が、クライアントは確かにこの情報を気にします。したがって、 にestimatedMinutesRemaining
は を使用して注釈が付けられ@Transient
ます。finalSolution
がアルゴリズムによって特定されると、. を使用せずに JPA によって直接永続化されProgressReport
ます。
フィールドが永続化されないようにするだけの場合は、一時的なものと @Transient の両方が機能します。しかし、問題は、transientがすでに存在するため、 @Transientがなぜ存在するのかということです。
@Transient フィールドは引き続きシリアル化されるためです。
エンティティを作成し、CPU を消費する計算を行って結果を取得するとします。この結果はデータベースに保存されません。ただし、エンティティを他の Java アプリケーションに送信して JMS で使用する場合@Transient
は、JavaSE キーワードではなくを使用する必要がありますtransient
。そのため、他の VM で実行されているレシーバーは、再計算する時間を節約できます。
「なぜ」という問いに答えてみます。テーブルに多数の列を持つ巨大なデータベースがあり、プロジェクト/システムがツールを使用してデータベースからエンティティを生成する状況を想像してみてください。(Hibernateにはそれらがあります...) さて、ビジネスロジックによって、特定のフィールドを永続化しない必要があるとします。特定の方法でエンティティを「構成」する必要があります。Transient キーワードは Java 言語内で動作するため、オブジェクトに対して機能しますが、@Transient は永続化タスクのみに関連するタスクに応答するように設計されています。