この章では、特にOracle Databaseプラットフォームをサポートするよう設計されたOracle TopLinkのEclipseLinkの機能を理解して使用する方法を説明します。
この章の内容は次のとおりです。
ユース・ケース
Oracle TopLinkには、すべてのデータベースに対応するよう設計された永続性ソリューションが用意されています。ただし、アプリケーションでOracle Databaseプラットフォームを使用する計画の場合は、Oracle Databaseに対する高度なサポートを利用できます。
解決方法
このソリューションは、TopLinkの様々なAPIやOracle製品によって実現されています。使用しているOracle Databaseの機能や製品に基づいて、アプリケーションで様々なOracle TopLinkのAPIの実装を選択します。
コンポーネント
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の追加機能が含まれています。 |
Oracle Database
アプリケーションで使用することが選択された機能に応じ、その他のOracle DatabaseおよびMiddleware製品が必要になります。
EclipseLinkでは、Oracle Databaseプラットフォームを拡張サポートしています。Oracle Databaseを標準とするアプリケーションでは、このサポートにより使い勝手、パフォーマンス、拡張性およびセキュリティが向上します。EclipseLinkでは、Oracle JDBC固有のネイティブAPI、PL/SQL、Oracle Real Application Clusters (RAC)、Oracle仮想プライベート・データベース、Oracle Proxy AuthenticationおよびOracle Spatial and Graphをサポートしています。これらのテクノロジの詳細は、Oracle Databaseのドキュメントを参照してください。
Oracle Databaseプラットフォームに対するサポートの多くは、org.eclipse.persistence.platform.database.oracle*パッケージに含まれています。このAPIの詳細は、『Oracle TopLink Java APIリファレンス』を参照してください。
この項では、テクノロジごとのソリューションをまとめています。このようにまとめることにより、開発者はソリューションの様々な部分を簡単に理解して、実装する部分を具体的に選択できます。
この章の内容は次のとおりです。
Oracle Databaseプラットフォームに対するサポートは、org.eclipse.persistence.platform.database.OraclePlatformクラス、org.eclipse.persistence.platform.database.oracle*パッケージで提供され、Oracle XML Databaseに対するサポートはorg.eclipse.persistence.mappings.xdbパッケージで提供されています。このAPIの詳細は、『Oracle TopLink Java APIリファレンス』を参照してください。特定のOracle SQL型の詳細は、『Oracle Database JDBC Java APIリファレンス』を参照してください。
Oracle Databaseでは次がサポートされています。
オプティミスティック・ロックを使用したバッチ書込み
byte[]、Date、Time、TimestampおよびCalendarのネイティブSQL
大きな値に対してOracle JDBC固有のLOBLocatorを使用した、BLOBおよびCLOBデータ型に対するサポート
|
注意: Thinドライバがラップされている非Oracle Thin JDBCドライバおよびアプリケーション環境では、プラットフォーム・インスタンスで |
Outer Join構文 (+) = のネイティブ・サポート
ネイティブ順序付け (SELECT SEQ_NAME.NEXTVAL FROM DUAL)
MaxRowsおよびFirstResultフィルタリングのネイティブSQL/ROWNUMサポート
階層Select (connect by prior)
RETURNING句
カスタム式関数(REGEXP_LIKE、LOCATE、ATAN2、LOG、CONCAT、SYSDATE (Date、Time、Today)、EXCEPT)
起動、パラメータ渡し、出力パラメータおよび出力カーソル用のPLSQLデータ型、ストアド関数、ストアド・プロシージャ構文。24.2.2項「EclipseLinkでのOracle PL/SQLの使用」を参照してください。
SYSDATEおよびSYSTIMESTAMPを使用したオプティミスティック・ロックで使用するためのタイムスタンプ問合せ
NCHAR、NSTRINGおよびNCLOBでのマルチバイトのサポート
TIMESTAMP、TIMESTAMPTZおよびTIMESTAMPLTZのサポート
XMLTypeフィールドおよびカスタムXSQL関数のOracle XML Databaseのサポート(extract、extractValue、existsNode、isFragment、getStringValおよびgetNumberVal)
XDK XMLパーサー
履歴セッションでのフラッシュバック問合せ
オブジェクト・リレーショナル・マッピング(ReferenceMapping、StructureMapping、NestedTableMapping、ArrayMapping、ObjectArrayMapping)
Oracle AQ
Oracle Real Application Clusters。24.2.5項「Oracle RACでのEclipseLinkの使用」を参照してください。
Oracle Label Securityを含む仮想プライベート・データベース(VPD)。24.2.3項「Oracle仮想プライベート・データベースの使用」を参照してください。
プロキシ認証。24.2.4項「Oracle Proxy Authenticationの使用」を参照してください。
EclipseLinkには、Oracle PL/SQLで使用するAPIが含まれています。このAPIは、org.eclipse.persistence.platform.database.oracle.plsqlパッケージとorg.eclipse.persistence.platform.database.oracle.annotationsパッケージにあります。
この項の内容は次のとおりです。
Oracle PL/SQLのストアド関数は、RECORD型やTABLE型などの複雑なPL/SQLデータ型を返すために使用できます。PL/SQL型は、Oracle JDBCではサポートされていないので、これらの型はOracle OBJECT型やVARRAY型に変換する必要があります。JDBCでOBJECT型はjava.sql.Structとして返され、VARRAYはjava.sql.Array型として返されます。
PL/SQLストアド関数およびプロシージャの実行には、RECORDおよびTABLE型にミラーOBJECTおよびVARRAY型を定義する必要があります。OBJECT型は、@Struct注釈を使用し、@Entityまたは@Embeddableのいずれかで注釈されたクラスにマップできます。OBJECT型でIdが定義され、表にストアできる場合を除き、通常は@Embeddableの注釈がついたクラスが使用されます。ネストされるOBJECTおよびVARRAY型は、@Structureおよび@Array注釈を使用してマップされます。
PL/SQL型を使用してストアド関数を呼び出すには、PLSQLStoredFunctionCallクラスまたは@NamedPLSQLStoredFunctionQuery注釈を使用します。ストアド・プロシージャ用にPLSQLStoredProcedureCallクラスおよび@NamedPLSQLStoredProcedureQuery注釈もあります。複雑なPL/SQL型を返さないストアド関数およびプロシージャには、StoredFunctionCallクラス、@NamedStoredFunctionQuery注釈、StoredProcedureCallクラス、@NamedStoredProcedureQuery注釈を使用します。
Oracle PL/SQLストアド関数を実行するには、次の手順を実行します。
CREATE OR REPLACE PACKAGE EMP_PKG AS TYPE EMP_REC IS RECORD (F_NAME VARCHAR2(30), L_NAME VARCHAR2(30), SALARY NUMBER(10,2)); FUNCTION GET_EMP RETURN EMP_REC; END EMP_PKG; CREATE OR REPLACE PACKAGE BODY EMP_PKG AS FUNCTION GET_EMP RETURN EMP_REC AS P_EMP EMP_REC; BEGIN P_EMP.F_NAME := 'Bob'; P_EMP.F_NAME := 'Smith'; P_EMP.SALARY := 30000; RETURN P_EMP; END; END EMP_PKG;
CREATE OR REPLACE TYPE EMP_TYPE AS OBJECT (F_NAME VARCHAR2(30), L_NAME VARCHAR2(30), SALARY NUMBER(10,2))
@Embeddable
@Struct(name="EMP_TYPE", fields={"F_NAME", "L_NAME", "SALARY"})
public class Employee {
@Column(name="F_NAME")
private String firstName;
@Column(name="L_NAME")
private String lastName;
@Column(name="SALARY")
private BigDecimal salary;
...
}
import javax.persistence.Query;
import org.eclipse.persistence.platform.database.orcle.plsql.
PLSQLStoredFunctionCall;
import org.eclipse.persistence.queries.ReadAllQuery;
DataReadQuery databaseQuery = new DataReadQuery();
databaseQuery.setResultType(DataReadQuery.VALUE);
PLSQLrecord record = new PLSQLrecord();
record.setTypeName("EMP_PKG.EMP_REC");
record.setCompatibleType("EMP_TYPE");
record.setJavaType(Employee.class);
record.addField("F_NAME", JDBCTypes.VARCHAR_TYPE, 30);
record.addField("L_NAME", JDBCTypes.VARCHAR_TYPE, 30);
record.addField("SALARY", JDBCTypes.NUMERIC_TYPE, 10, 2);
PLSQLStoredFunctionCall call = new PLSQLStoredFunctionCall(record);
call.setProcedureName("EMP_PKG.GET_EMP");
databaseQuery.setCall(call);
Query query = ((JpaEntityManager)entityManager.getDelegate()).
createQuery(databaseQuery);
Employee result = (Employee)query.getSingleResult();
@NamedPLSQLStoredFunctionQuery(name="getEmployee", functionName="EMP_PKG.GET_EMP",
returnParameter=@PLSQLParameter(name="RESULT", databaseType="EMP_PKG.EMP_REC"))
@Embeddable
@Struct(name="EMP_TYPE", fields={"F_NAME", "L_NAME", "SALARY"})
@PLSQLRecord(name="EMP_PKG.EMP_REC", compatibleType="EMP_TYPE",
javaType=Employee.class,fields={@PLSQLParameter(name="F_NAME"),
@PLSQLParameter(name="L_NAME"), @PLSQLParameter(name="SALARY",
databaseType="NUMERIC_TYPE")})
public class Employee {
...
}
Query query = entityManager.createNamedQuery("getEmployee");
Employee result = (Employee)query.getSingleResult();
一般的に、ストアド・プロシージャは、StoredProcedureCallクラスのインスタンスを構築して処理します。ただし、引数がJDBCの仕様に準拠している必要があります。Oracle PL/SQLの引数(たとえば、BOOLEAN、PLS_INTEGER、PL/SQLレコードなど)を処理するには、PLSQLStoredProcedureCallクラスを使用します。
|
注意:
|
次に、PLSQLStoredProcedureCallクラスを使用してPL/SQL引数を処理する方法を示します。この例は、次のターゲット・プロシージャに基づいています。
PROCEDURE bool_in_test(x IN BOOLEAN)
PLSQLStoredProcedureCallクラスを使用した例
import java.util.List;
import java.util.ArrayList;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.platform.database.jdbc.JDBCTypes;
import org.eclipse.persistence.platform.database.oracle.Oracle10Platform;
import org.eclipse.persistence.platform.database.oracle.OraclePLSQLTypes;
import org.eclipse.persistence.platform.database.oracle.PLSQLStoredProcedureCall;
import org.eclipse.persistence.queries.DataModifyQuery;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.Session;
public class TestClass {
public static String DATABASE_USERNAME = "username";
public static String DATABASE_PASSWORD = "password";
public static String DATABASE_URL = "jdbc:oracle:thin:@localhost:1521:ORCL";
public static String DATABASE_DRIVER = "oracle.jdbc.driver.OracleDriver";
public static void main(String[] args) {
Project project = new Project();
DatabaseLogin login = new DatabaseLogin();
login.setUserName(DATABASE_USERNAME);
login.setPassword(DATABASE_PASSWORD);
login.setConnectionString(DATABASE_URL);
login.setDriverClassName(DATABASE_DRIVER);
login.setDatasourcePlatform(new Oracle10Platform());
project.setDatasourceLogin(login);
Session s = project.createDatabaseSession();
s.setLogLevel(SessionLog.FINE);
((DatabaseSession)s).login();
PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall();
call.setProcedureName("bool_in_test");
call.addNamedArgument("X", OraclePLSQLTypes.PLSQLBoolean);
DataModifyQuery query = new DataModifyQuery();
query.addArgument("X");
query.setCall(call);
List queryArgs = new ArrayList();
queryArgs.add(Integer.valueOf(1));
s.executeQuery(query, queryArgs);
}
}
次に、無名PL/SQLブロックからターゲットのプロシージャを起動した場合のログの抜粋を示します。
...[EclipseLink Info]: 2007.11.23 01:03:23.890--DatabaseSessionImpl(15674464)-- Thread(Thread[main,5,main])-- login successful [EclipseLink Fine]: 2007.11.23 01:03:23.968--DatabaseSessionImpl(15674464)-- Connection(5807702)--Thread(Thread[main,5,main])-- DECLARE X_TARGET BOOLEAN := SYS.SQLJUTL.INT2BOOL(:1); BEGIN bool_in_test(X=>X_TARGET); END; bind => [:1 => 1]
|
注意:
|
ストアド・プロシージャに対して、通常のJDBCと非JDBC引数が混在している場合があります。少なくとも1つの引数が非JDBC型である場合はPLSQLStoredProcedureCallクラスを使用します。また、ターゲットのプロシージャが無名PL/SQLブロックから起動されるので、(長さ、スケール、精度の)JDBC型にはいくつか追加情報を追加する必要があります。この例は、次のターゲット・プロシージャに基づいています。
PROCEDURE two_arg_test(x IN BOOLEAN, y IN VARCHAR)
JDBC引数と非JDBC引数の混在の例
import org.eclipse.persistence.platform.database.jdbc.JDBCTypes;
...
PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall();
call.setProcedureName("two_arg_test");
call.addNamedArgument("X", OraclePLSQLTypes.PLSQLBoolean);
call.addNamedArgument("Y", JDBCTypes.VARCHAR_TYPE, 40);
DataModifyQuery query = new DataModifyQuery();
query.addArgument("X");
query.addArgument("Y");
query.setCall(call);
List queryArgs = new ArrayList();
queryArgs.add(Integer.valueOf(0));
queryArgs.add("test");
boolean worked = false;
String msg = null;
s.executeQuery(query, queryArgs);
次に、無名PL/SQLブロックからターゲットのプロシージャを起動した場合のログの抜粋を示します。
[EclipseLink Fine]: 2007.11.23 02:54:46.109--DatabaseSessionImpl(15674464)-- Connection(5807702)--Thread(Thread[main,5,main])-- DECLARE X_TARGET BOOLEAN := SYS.SQLJUTL.INT2BOOL(:1); Y_TARGET VARCHAR(40) := :2; BEGIN two_arg_test(X=>X_TARGET, Y=>Y_TARGET); END; bind => [:1 => 0, :2 => test]
次に、次のターゲット・プロシージャに基づくINおよびOUT引数を両方含む、ストアド・プロシージャの例を示します。
PROCEDURE two_arg_in_out(x OUT BINARY_INTEGER, y IN VARCHAR) AS BEGIN x := 33; END;
INおよびOUT引数の処理の例
import static org.eclipse.persistence.platform.database.oracle.OraclePLSQLTypes.
BinaryInteger;
...
PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall();
call.setProcedureName("two_arg_in_out");
call.addNamedOutputArgument("X", OraclePLSQLTypes.BinaryInteger);
call.addNamedArgument("Y", JDBCTypes.VARCHAR_TYPE, 40);
DataReadQuery query = new DataReadQuery();
query.setCall(call);
query.addArgument("Y");
List queryArgs = new ArrayList();
queryArgs.add("testsdfsdfasdfsdfsdfsdfsdfsdfdfsdfsdffds");
boolean worked = false;
String msg = null;
List results = (List)s.executeQuery(query, queryArgs);
DatabaseRecord record = (DatabaseRecord)results.get(0);
BigDecimal x = (BigDecimal)record.get("X");
if (x.intValue() != 33) {
System.out.println("wrong x value");
}
次に、無名PL/SQLブロックからターゲットのプロシージャを起動した場合のログの抜粋を示します。
[EclipseLink Fine]: 2007.11.23 03:15:25.234--DatabaseSessionImpl(15674464)-- Connection(5807702)--Thread(Thread[main,5,main])-- DECLARE Y_TARGET VARCHAR(40) := :1; X_TARGET BINARY_INTEGER; BEGIN two_arg_in_out(X=>X_TARGET, Y=>Y_TARGET); :2 := X_TARGET; END; bind => [:1 => testsdfsdfasdfsdfsdfsdfsdfsdfdfsdfsdffds, X => :2]
|
注意: 実行時に引数をバインドする順序を変更する必要があります。無名PL/SQLブロックでは、最初にすべてのIN引数の順序マーカーを処理し( |
無名PL/SQLブロックでは、IN OUT引数をネイティブで処理できません。引数はINの半分とOUTの半分の2つに分割する必要があります。次に、次のターゲット・プロシージャに基づいてIN OUT引数を処理するストアド・プロシージャの例を示します。
PROCEDURE two_args_inout(x VARCHAR, y IN OUT BOOLEAN) AS BEGIN y := FALSE; END;
IN OUT引数の処理の例
...
PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall();
call.setProcedureName("two_args_inout");
call.addNamedArgument("X", JDBCTypes.VARCHAR_TYPE, 20);
call.addNamedInOutputArgument("Y", OraclePLSQLTypes.PLSQLBoolean);
DataReadQuery query = new DataReadQuery();
query.addArgument("X");
query.addArgument("Y");
query.setCall(call);
List queryArgs = new ArrayList();
queryArgs.add("test");
queryArgs.add(Integer.valueOf(1));
List results = (List)s.executeQuery(query, queryArgs);
DatabaseRecord record = (DatabaseRecord)results.get(0);
Integer bool2int = (Integer)record.get("Y");
if (bool2int.intValue() != 0) {
System.out.println("wrong bool2int value");
}
次に、無名PL/SQLブロックからターゲットのプロシージャを起動した場合のログの抜粋を示します。
[EclipseLink Fine]: 2007.11.23 03:39:55.000--DatabaseSessionImpl(25921812)-- Connection(33078541)--Thread(Thread[main,5,main])-- DECLARE X_TARGET VARCHAR(20) := :1; Y_TARGET BOOLEAN := SYS.SQLJUTL.INT2BOOL(:2); BEGIN two_args_inout(X=>X_TARGET, Y=>Y_TARGET); :3 := SYS.SQLJUTL.BOOL2INT(Y_TARGET); END; bind => [:1 => test, :2 => 1, Y => :3]
|
注意:
|
EclipseLinkでは、Oracle仮想プライベート・データベース(VPD)をサポートしています。Oracle VPDはサーバーで実行される、精度の高い制御メカニズムです。Oracle VPDは、条件付きのSQL文を動的に追加して行レベルでデータ・アクセスを制限する形で、セキュリティ・ポリシーを表に関連付けます。セキュリティ・ポリシーは、独自に作成することも、Oracle Label Security (OLS)と呼ばれるOracleカスタム実装を使用することもできます。Oracle VPDの詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください。Oracle Label Securityの詳細は、『Oracle Label Security管理者ガイド』を参照してください。
マルチテナンシでOracle VPDを使用する方法の詳細は、14.4項「VPDマルチテナンシの使用」を参照してください。
EclipseLinkアプリケーションでOracle Database VPD機能を使用するには、独立したキャッシュを使用する必要があります。Oracle VPDを使用する表にマップされているエンティティには、独立済と構成されている識別子が必要です。また、通常排他接続を使用する必要があります。
Oracle VPDをサポートするには、永続性コンテキストのライフ・サイクルの間に起動されるセッション・イベント・ハンドラを実装する必要があります。どのようなセッション・イベント・ハンドラを実装する必要があるかは、Oracle Databaseプロキシ認証を使用しているかに依存します。
Oracle VPDとOracle Databaseのプロキシ認証
Oracle Databaseでプロキシ認証を使用すると、データベース内でOracle VPDに対するサポートを完全に設定することができます。つまり、セッション・イベント・ハンドラがSQLを実行するかわりに、プロキシsession_userを使用して、データベースがログイン・トリガー後に必要な設定を行います。
Oracleプロキシ認証の使用方法の詳細は、24.2.4項「Oracleプロキシ認証の使用」を参照してください。
Oracle Databaseのプロキシ認証を使用しないOracle VPD
Oracle Databaseのプロキシ認証を使用しない場合は、次のセッション・イベントでセッション・イベント・ハンドラを実装する必要があります。
postAcquireExclusiveConnection: 独立セッションに専用接続が割り当てられ、独立セッション・ユーザーがデータベースとの通信に接続を使用する前に、Oracle VPDの設定を実行するために使用します。
preReleaseExclusiveConnection: 独立セッションが解放され、ユーザーがデータベース通信を終了した後のVPDクリーン・アップの実行に使用します。
これらのハンドラの実装では、必要なユーザー資格証明は関連付られているセッションのプロパティから取得します。
JPAとEclipseLinkは、通常、共有接続プールとともに中間層/サーバー環境で使用されます。接続プールでは、データベース接続が共有されるので、データベースに再接続するためのコストを回避できます。通常、ユーザーはアプリケーションにログインしますが、接続プール用には共有のログインが使用されるので、ユーザーは独自のデータベース・ログインは持ちません。これは、プロキシ・ユーザーを既存のデータベース接続に設定するメカニズムです。これは共有接続プールの使用を可能にする一方で、データベースにユーザー・コンテキストを与えます。
Oracleプロキシ認証は、EntityManagerオブジェクトに次の永続性ユニット・プロパティを使用して構成します。
"eclipselink.oracle.proxy-type" : oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME, PROXYTYPE_CERTIFICATE, PROXYTYPE_DISTINGUISHED_NAME
oracle.jdbc.OracleConnection.PROXY_USER_NAME : user_name
oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD : password
oracle.jdbc.OracleConnection.PROXY_DISTINGUISHED_NAME
oracle.jdbc.OracleConnection.PROXY_CERTIFICATE
oracle.jdbc.OracleConnection.PROXY_ROLES
|
注意: デフォルトで、この接続は書込みのみに使用され、読取りでは、共有接続プールが使用されます。読取りでもこの接続を使用するよう強制するには、 |
プロキシ認証を設定するには、EntityManagerオブジェクトを作成し、永続性ユニット・プロパティを設定します。次に例を3つ示します。
タスク: 書込みのみ監査
書込みのみを監査する場合のプロキシ認証の設定:
Map properties = new HashMap();
properties.put("eclipselink.oracle.proxy-type",
oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME);
properties.put(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user);
properties.put(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password);
properties.put("eclipselink.jdbc.exclusive-connection.mode", "Transactional");
properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "true");
EntityManager em = factory.createEntityManager(properties);
タスク: 読取りおよび書込みの監査
読取りおよび書込みを監査する場合のプロキシ認証の設定:
Map properties = new HashMap();
properties.put("eclipselink.oracle.proxy-type",
oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME);
properties.put(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user);
properties.put(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password);
properties.put("eclipselink.jdbc.exclusive-connection.mode", "Always");
properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
EntityManager em = factory.createEntityManager(properties);
タスク: Java EEアプリケーションでのプロキシ認証の構成
JEEおよびJTAで管理されているエンティティ・マネージャを使用する場合、エンティティ・マネージャとJDBC接続はアプリケーションでは制御されないので、プロキシ・ユーザーとパスワードの指定はより困難になります。ただし、データベース接続を確立する前であれば、EntityManagerオブジェクトに永続性ユニット・プロパティを指定できます。
JPA 2.nを使用する場合、setProperty APIを使用できます。
em.setProperty("eclipselink.oracle.proxy-type",
oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME);
em.setProperty(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user);
em.setProperty(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password);
em.setProperty("eclipselink.jdbc.exclusive-connection.mode", "Always");
em.setProperty("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
これ以外の場合は、getDelegate APIを使用します。
Map properties = new HashMap();
properties.put("eclipselink.oracle.proxy-type",
oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME);
properties.put(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user);
properties.put(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password);
properties.put("eclipselink.jdbc.exclusive-connection.mode", "Always");
properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
((org.eclipse.persistence.internal.jpa.EntityManagerImpl)em.getDelegate()).
setProperties(properties);
デフォルトでは、EclipseLinkは共有(L2)オブジェクトのキャッシュを維持します。これは監査には問題がありませんが、Oracle VPDまたはユーザー・ベースのセキュリティが使用され、特定の表やクラスの読み取りができないようになっている場合、これらのセキュア・クラスのキャッシュを無効にする必要がある場合があります。共有キャッシュを無効にする方法の詳細は、「エンティティ・キャッシュの無効化」を参照してください。
データベース・ユーザーが読取りのセキュリティを確認することに慣れている場合、eclipselink.jdbc.exclusive-connection.modeプロパティをIsolatedに設定して、共有キャッシュが無効(独立)になっているクラスの読取りに対してのみユーザー接続使用されるようにします。
Oracle仮想プライベート・データベース(VPD)機能では、Oracle Databaseで行レベルのセキュリティを確保できます。通常、データベース・セキュリティでは、表レベルでしかアクセス権限を設定できせん。行レベルでセキュリティを使用できる場合、各ユーザーは各表の別の行にアクセスできます。
Oracle VPDをサポートするには、EclipseLinkのOracleプロキシ認証機能を使用します。プロキシ・ユーザーは、行レベルでセキュリティがチェックされます。Oracle VPDを使用する場合、セキュリティで保護されたオブジェクトは共有できないので、これらの共有キャッシュを無効にすることも同様に重要です。共有キャッシュを無効にする方法の詳細は、「エンティティ・キャッシュの無効化」を参照してください。
Oracle Real Application Clusters (RAC)では、Oracle Databaseを拡張して、別のサーバーの複数のデータベース・インスタンスを同時に使用して効率的にデータをストア、更新および取得できます。Oracle RACは、複数のサーバーをインスタンスおよび1つのグループとして管理するソフトウェアを提供します。アプリケーションはOracle RAC機能を使用して、接続のパフォーマンスおよび可用性を最大化し、接続の問題による停止時間を軽減します。アプリケーションの可用性およびパフォーマンスに対する要件は一様ではないため、それに応じてOracle RAC機能を実装する必要があります。Oracle RACの詳細は、『Oracle Real Application Clusters管理およびデプロイメント・ガイド』を参照してください。
Oracle DatabaseおよびOracle WebLogic Serverにはいずれも接続プールを実装でき、これでRACデータベースへ接続して様々なOracle RACの機能を利用できます。それらの機能には、高速接続フェイルオーバー(FCF)、実行時接続ロード・バランシング(RCLB)および接続アフィニティがあります。WebLogic Serverでは、RACが有効なデータベースに接続するために、アプリケーションでJDBCデータ・ソース(マルチ・データ・ソースまたはGridLinkデータ・ソース)が作成されます。スタンドアロン・アプリケーションでは、Universal Connection Pool (UCP) JDBC接続プールAPI (ucp.jar)が使用されて、データ・ソースが作成されます。いずれの接続プールも、実装するにはOracle Notification Serviceライブラリ(ons.jar)が必要です。このライブラリは、接続プールがRACイベントを登録およびリスニングする主要な手段です。これらのテクノロジに詳しくない場合は、『Oracle Universal Connection Pool for JDBC開発者ガイド』および『Oracle WebLogic Server JDBCデータ・ソースの管理』を参照してください。
この項は、Oracle JDBCドライバおよびOracle RACが有効なデータベースがあることが前提です。RACが有効なデータベースが動作し、接続URLがわかっている必要があります。また、ons.jarファイルを含むデータベースOracle Clientソフトウェアをダウンロードする必要があります。ucp.jarファイルは、Oracle Databaseに含まれています。
この項のタスクは、Oracle WebLogic Serverに実装されている永続性アプリケーションからRACが有効なデータベースに接続するために使用します。
Oracle RAC用にWebLogic Serverにデータ・ソースを構築する方法の詳細は、第3章「WebLogic ServerでのTopLink の使用」および『Oracle WebLogic Server JDBCデータ・ソースの管理』を参照してください。
persistence.xmlファイルを編集し、永続性ユニットの構成にデータ・ソース名を含めます。次に例を示します。
<persistence-unit name="OrderManagement"> <jta-data-source>jdbc/MyOrderDB</jta-data-source> ... </persistence-unit>
この項のタスクは、スタンドアロン永続性アプリケーションからRACデータベースに接続するために使用します。これらのタスクでは、高度なRACの機能で必要なUCPデータ・ソースを使用する方法を説明します。
UCPデータ・ソースは、RACデータベースへの接続に使用します。データ・ソースでは高度なRAC構成を指定できます。UCPを使用した高度なRAC機能の使用方法の詳細は、『Oracle Universal Connection Pool for JDBC開発者ガイド』を参照してください。次の例では、データ・ソースを作成し、FCFを有効にし、ONSを構成します。
PoolDataSource datasource = PoolDataSourceFactory.getPoolDataSource(); datasource.setONSConfiguration(”nodes=host1:4200,host2:4200”); datasource.setFastConnectionFailoverEnabled(true); datasource.setConnectionFactoryClassName(”oracle.jdbc.pool.OracleDataSource”); datasource.setURL(”jdbc:oracle:thin:@DESCRIPTION= (LOAD_BALANCE=on) (ADDRESS=(PROTOCOL=TCP)(HOST=host1)(PORT=1521)) (ADDRESS=(PROTOCOL=TCP)(HOST=host2)(PORT=1521)) (ADDRESS=(PROTOCOL=TCP)(HOST=host3)(PORT=1521)) (ADDRESS=(PROTOCOL=TCP)(HOST=host4)(PORT=1521)) (CONNECT_DATA=(SERVICE_NAME=service_name)))”);
RACやUCPの高度な機能を必要としないアプリケーションからは、EclipseLinkにネイティブな接続プールを使用してRACが有効なデータベースに接続できます。この場合、アプリケーションのpersistence.xmlファイルを編集し、永続性ユニット用にRACのURLの接続文字列を追加します。次に例を示します。
<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_1_0.xsd" version="1.0">
<persistence-unit name="my-app" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver"
value="oracle.jdbc.OracleDriver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:oracle:thin@(DESCRIPTION= "+ "(LOAD_BALANCE=on)"+
"(ADDRESS=(PROTOCOL=TCP)(HOST=rac_node) (PORT=1521))"+
"(ADDRESS=(PROTOCOL=TCP)(HOST=racnode2) (PORT=1521))"+
"(CONNECT_DATA=(SERVICE_NAME=service_name))")"/>
<property name="javax.persistence.jdbc.user" value="user_name"/>
<property name="javax.persistence.jdbc.password" value="password"/>
</properties>
</persistence-unit>
</persistence>
永続性ユニットを使用するには、次のようにEntityManagerFactoryをインスタンス化します。
Persistence.createEntityManagerFactory("my-app");
UCPデータ・ソースを使用するには、次のようにEntityManagerFactoryをインスタンス化し、データ・ソースを渡します。
Map properties = new HashMap();
properties.add("javax.persistence.nonJtaDataSource", datasource);
Persistence.createEntityManagerFactory(properties);
EclipseLinkには、Oracle DatabaseでOracle Spatial and Graphデータを問い合せる際のサポートが追加されています。Oracle Spacial and Graphは、アプリケーションで位置を有効にするために使用できます。これには、空間データおよび空間分析、物理グラフ、論理グラフ、ネットワーク・グラフ、ソーシャル・グラフおよびセマンティック・グラフ・アプリケーション用の高度な機能が含まれています。空間フィーチャは、Oracle Databaseへの空間フィーチャの集合の格納、検索、更新および問合せを容易にするスキーマおよびファンクションを提供します。Oracle Spacial and Graphアプリケーションの開発の詳細は、『Oracle Spatial and Graph開発者ガイド』を参照してください。WebLogic ServerでOracle Spatial and Graphを使用する方法の詳細は、第3章「タスク7: Oracle Databaseの高度な機能を使用するためのドメインの拡張」を参照してください。
EclipseLinkアプリケーションでは、Oracle Spacial and Graphの演算子を使用する式を構築できます。詳細は、org.eclipse.persistence.expressions.spatial APIを参照してください。次に例を示します。
ExpressionBuilder builder = new ExpressionBuilder(); Expression withinDistance = SpatialExpressions.withinDistance(myJGeometry1, myJGeometry2, "DISTANCE=10"); session.readAllObjects(GeometryHolder.class, withinDistance);
次の例では、oracle.spatial.geometry.JGeometryオブジェクトが必要です。EclipseLinkのorg.eclipse.persistence.platform.database.oracle.converters.JGeometryConverterコンバータを使用し、Oracle Databaseから読み書きされるようにJGeometryオブジェクトを変換します。JGeometryConverterオブジェクトはaddStructConverter(StructConverter)メソッドまたはsessions.xmlファイルに指定して、Oracle Databaseプラットフォームに追加する必要があります。JGeometryタイプもクラスパスで存在する必要があります。
次に、Oracle Spatialに問合せを実行するために、FUNCTION JPA拡張を使用する方法を示します。FUNCTIONの拡張の詳細は、『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』を参照してください。
SELECT a FROM Asset a, Geography geo WHERE geo.id = :id AND a.id IN :id_list AND
FUNCTION('ST_INTERSECTS', a.geometry, geo.geometry) = 'TRUE'
SELECT s FROM SimpleSpatial s WHERE FUNCTION('MDSYS.SDO_RELATE', s.jGeometry,
:otherGeometry, :params) = 'TRUE' ORDER BY s.id ASC
この章で説明しているソリューションのその他の参考資料については、次のリンクを参照してください。
『Oracle TopLink Java APIリファレンス』
『Oracle TopLink Java Persistence API (JPA)拡張機能リファレンス』
Oracle Database JDBC Java APIリファレンス
『Oracle Database PL/SQL言語リファレンス』
『Oracle Databaseセキュリティ・ガイド』
『Oracle Label Security管理者ガイド』
Oracle WebLogic ServerのJDBCデータ・ソースの管理
『Oracle Real Application Clusters管理およびデプロイメント・ガイド』
『Oracle Universal Connection Pool for JDBC開発者ガイド』
『Oracle Spatial and Graph開発者ガイド』