この章では、JPAの共有データベースでキャッシュを使用することを可能にするTopLinkデータベース変更通知(DCN)について説明します。
この章の内容は次のとおりです。
ユース・ケース
ユーザーが、JPAアプリケーションで共有キャッシュを使用したいと考えていますが、外部アプリケーションによって同じデータベース・データが更新されてしまうか、キャッシュがクラスタ環境にあります。キャッシュには失効データが残ってしまう場合があります。
解決方法
TopLinkには、データベースがTopLinkにデータベースの変更を通知できるようにするAPIが用意されています。変更されたオブジェクトは、TopLinkの共有キャッシュで無効にできます。失効したデータは、他のアプリケーションがデータベース内の同じデータにアクセスする場合でも破棄されます。
コンポーネント
Oracle 11gR2 (11.2) (以上の)データベース
TopLink 12c (12.1.2.0.0)以上。
|
注意: TopLinkのコア機能は、オープン・ソースのEclipse Foundationの永続性フレームワークであるEclipseLinkによって提供されています。EclipseLinkでは、Java Persistence API (JPA)、Java Architecture for XML Binding (JAXB)、および標準に基づいたその他の永続性テクノロジと、それらの標準の拡張が実装されます。TopLinkには、EclipseLinkのすべてに加え、Oracleの追加機能が含まれています。 |
EclipseLinkライブラリ: eclipselink.jar。
JDBCライブラリ: ojdbc6.jar。
JPAライブラリ: persistence.jar。
例
JPAを使用するアプリケーションでデータベース変更通知および共有キャッシュの使用方法を示すサンプル・ファイルについては、EclipseLinkドキュメントのEclipseLink/Examples/JPA/DCNに関する項を参照してください。
http://wiki.eclipse.org/EclipseLink/Examples/JPA/DCN
EclipseLinkには、データベースのオブジェクトとリレーションシップに対するアクセスを減らす共有(L2)オブジェクト・キャッシュが用意されています。このキャッシュはデフォルトで有効で、他のアプリケーションまたはクラスタ環境において別のサーバーにある同じアプリケーションが、データベースの内容が直接変更しないかぎり通常は問題にはなりません。これによりキャッシュに無効なデータが生じる場合があります。
データベースの内容が変更された場合に、キャッシュの内容がデータベースと同期されることを保証するメカニズムが必要になります。このメカニズムは、EclipseLinkのデータベース変更通知によって提供されます。DCNでは、JPA環境で共有キャッシュを使用できます。
|
注意: データベース変更通知は、Oracle Databaseの連続問合せ通知機能によって提供される機能の拡張版です。詳細は、『Oracle Database JDBC開発者ガイド』の連続問合せ通知に関する項を参照してください。 |
EclipseLinkのデータベース変更通知は、Oracle Databaseの連続問合せ通知機能によって提供される機能の拡張版です。連続問合せ通知の機能の1つは、表の中の行が変更されたときにデータベース・イベントが発生することがこの機能によって許可されることです。
変更を検出するために、EclipseLink DCNはROWIDを使用し、プライマリ表の行レベルの変更を通知します。EclipseLinkでは、DCN対応のクラスのすべての問合せにROWIDを含めます。EclipseLinkでは、Insert操作後にオブジェクトのROWIDも選択します。EclipseLinkでは、オブジェクトIdのみでなく、ROWIDのキャッシュ索引も維持します。EclipseLinkは、トランザクションを処理しているサーバーでキャッシュが無効にされないよう、トランザクションごとに1回データベースのトランザクションIDも選択します。
EclipseLink DCNは、OracleChangeNotificationListener (org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener)リスナー・クラスを介して有効にされます。リスナーはOracle JDBCと統合して、データベースの変更イベントを受け取ることができます。リスナーを有効にするには、persistence.xmlファイルでeclipselink.cache.database-event-listenerプロパティの値としてOracleChangeNotificationListenerクラスへの完全なパスを指定します。
デフォルトでは、ドメインのすべてのエンティティに対して変更通知が登録されます。ただし、変更通知は、JavaファイルのCache注釈のdatabaseChangeNotificationType (org.eclipse.persistence.annotations.DatabaseChangeNotificationType)属性でタグ付けして、特定のクラスを選んで無効にすることもできます。この属性の値によって、エンティティが使用するデータベースに対する変更通知の種類が決定されます。databaseChangeNotificationType属性のデフォルト値はInvalidateです。クラスの変更通知を無効にするには、属性の値をNoneに設定します。
databaseChangeNotificationType属性は、永続性ユニットにデータベースの変更イベントを受け取るOracleChangeNotificationListenerクラスなどのデータベース・イベント・リスナーが構成されている場合のみ該当します。これによりデータベースに変更があったときに、EclipseLinkのキャッシュを無効にしたり、更新できます。
トランザクションでは、(失効データに対する書込みは失敗し、キャッシュが自動的に無効になる)オプティミスティック・ロックを使用することを強くお薦めします。エンティティに@Version注釈を含めると、プライマリ表のバージョン列には常に更新され、オブジェクトは常に無効化されます。
この項では、JPA環境で共有キャッシュを有効にする次のタスクについて説明します。
このソリューションでは、関心のある表がOracle 11gR2 (11.2)以上のデータベースに含まれ、それで作業していることが前提です。
他の許可に加え、データベース・ユーザーには、CHANGE NOTIFICATION権限が付与されている必要があります。これを実行するには、SYSなどのDBA権限を持っているか、データベース管理者にそれを適用してもらう必要があります。
grant change notification to user
次の例では、ユーザーSCOTTに変更通知権限を付与する例を示します。
...
define user="SCOTT"
define pass="tiger"
grant create session, alter session to &&user
/
grant resource, connect to &&user
/
grant select any dictionary to &&user
/
grant select any table to &&user
/
grant change notification to &&user
/
...
EclipseLinkライブラリのeclipselink.jar、JDBCライブラリのojdbc6.jar、JPAライブラリのpersistence.jarおよびドメイン・クラスがクラスパスにあることを確認します。
デフォルトでは、ドメインのすべてのエンティティが変更通知に参加します。参加するエンティティを制限するには、いくつかの方法があります。たとえば、エンティティ・クラスをorm.xmlファイルの<entity class...>要素に示し、persistence.xmlファイルの<exclude-unlisted-classes>要素に示し、JARファイルに含めることができます。
|
注意:
|
JavaファイルでCache注釈属性を使用して、エンティティ・クラスを除外することも可能です。詳細は、22.2.6.2項「変更通知からのクラスの除外(オプション)」を参照してください。
persistence.xmlファイルで<class>要素を使用して、エンティティ・クラスを指定することも可能です。次の例は、modelパッケージのOrder、OrderLineおよびCustomerクラスが変更通知に参加することを示します。完全なpersistence.xmlファイルの例は、例22-1を参照してください。
... <class>model.Order</class> <class>model.OrderLine</class> <class>model.Customer</class> ...
データベース・イベント・リスナーを指定するには、eclipselink.cache.database-event-listenerプロパティを使用します。org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListenerクラスは、EclipseLinkのデータベース変更通知のリスナーです。これによりデータベース・イベントによりEclipseLinkのキャッシュが無効になります。
次に、OracleChangeNotificationListenerクラスにeclipselink.cache.database-event-listenerプロパティを構成した例を示します。完全なpersistence.xmlファイルの例は、例22-1を参照してください。
...
<properties>
<property name="eclipselink.cache.database-event-listener" value="org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener"/>
</properties>
...
次を使用することも可能です。
<property name="eclipselink.cache.database-event-listener" value="DCN">
persistence.xmlファイルの完全な例を例22-1に示します。変更通知に参加するクラスは、modelパッケージのOrder、OrderLineおよびCustomerクラスです。eclipselink.cache.database-event-listenerプロパティは、OracleChangeNotificationListenerクラスの完全パスに設定されます。
|
注意: EclipseLinkがデフォルトのプロバイダであるコンテナで実行される場合、 |
例22-1 persistence.xmlのサンプル・ファイル
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd"
version="2.0">
<persistence-unit name="acme" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>model.Order</class>
<class>model.OrderLine</class>
<class>model.Customer</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.cache.database-event-listener" value="DCN"/>
</properties>
</persistence-unit>
</persistence>
通常、変更通知に参加する場合、データベース表に対応するJavaクラスは変更する必要がありません。ただし、@Version注釈でオプティミスティック・ロックを設定することが強く推奨されます。
永続性ユニットに列挙されるクラスを除外したい場合は、Javaファイルでタグ付けします。EclipseLinkはプライマリ表でのみ変更を追跡します。セカンダリ表も追跡されるよう変更するには、Javaファイルにそれを示します。
失効データに対する書込みが失敗し、キャッシュを自動的に無効にするオプティミスティック・ロックを使用することを強くお薦めします。エンティティに@Version注釈を含めると、プライマリ表のバージョン列は常に更新されるので、古いバージョンのオブジェクトは常に無効化されます。
例22-2では、@Version注釈はCustomerエンティティに定義されています。versionの変数としてgetterおよびsetterが定義されていることに注意してください。
例22-2 @Version注釈の定義
...
@Entity
@Table(name="DBE_CUSTOMER")
public class Customer implements Serializable {
@Id
@GeneratedValue(generator="CUST_SEQ")
@TableGenerator(name="CUST_SEQ")
@Column(name="CUST_NUMBER")
private long id;
@Version
private long version;
...
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
...
Cache注釈のdatabaseChangeNotificationType属性を使用すると、変更通知を必要としないクラスを指定できます。変更通知からクラスを除外するには、次の例のとおり、属性をDatabaseChangeNotificationType.NONEに設定します。
...
@Entity
@Cache(databaseChangeNotificationType=DatabaseChangeNotificationType.NONE)
public class Order {
...
EclipseLinkはプライマリ表でのみ変更を追跡します。セカンダリ表で更新が発生する場合、EclipseLinkはオブジェクトを無効にしません。セカンダリ表でも同様に追跡するには、エンティティに@Version注釈を追加します。
Oracle DCNでは、プライマリ表のイベントのみをリスニングします。セカンダリ表またはリレーションシップ表の変更は追跡しません。この理由は、Oracle DCNがROWIDのみを追跡し、プライマリ表、セカンダリ表およびリレーションシップ表のROWIDには相関関係がないためです。したがって、セカンダリ表またはリレーションシップ表が変更されたときにイベントを受け取るには、プライマリ表のバージョンを変更してイベントが返されるようにする必要があります。
EclipseLinkのデータベース変更通知には次の制約があります。
プライマリ表で@Version注釈が使用され更新されないかぎり、オブジェクトのセカンダリ表が変更されてもその無効化はトリガーされません。
プライマリ表で@Version注釈が使用され更新されないかぎり、オブジェクトのOneToMany、ManyToManyおよびElementCollectionのリレーションシップが変更されてもその無効化はトリガーされません。
この章のソリューションが実装されているその他のテクノロジおよびツールの詳細は、次の参考資料を参照してください。
『Oracle Database JDBC開発者ガイド』の連続問合せ通知に関する項
「EclipseLink/Examples/JPA/DCN」: このページでは、DCNを採用しているJPA環境でのキャッシュ共有の例を説明しています。例を実行するサンプル・ファイルおよび手順が含まれています。EclipseLinkのドキュメントを参照してください。