Oracle RACを使用したアプリケーション・コンティニュイティのJava例 (2023/05/31)

Oracle RACを使用したアプリケーション・コンティニュイティのJava例 (2023/05/31)

https://database-heartbeat.com/2023/05/31/java-ac-rac/




はじめに


Oracle Application Continuity(アプリケーション・コンティニュイティ)は、データベースの中断をエンドユーザーやアプリケーションから隠します。SQL*Plusを使用した簡単なテストについては、このブログ記事で説明します。ただし、SQL*Plusは通常、本番で使用する実際のアプリケーションではありません。また、SQL*Plusはプールされたアプリケーションではなく、アプリケーション・コンティニュイティに接続プールを使用することをお薦めします。


このブログ投稿は、Oracle RACデータベースへのクイック・スタート接続のためのUniversal Connection Pool (UCP)を持つJDBCドライバを使用する単純なJavaの例を示しています。本番実装の推奨事項の完全なリストは、この投稿の最後にある公式のOracleドキュメントを参照してください。



環境


  • Oracle Cloud上で稼働する2ノードのOracle RACデータベース・バージョン19.17
  • Java JDK 11
  • ローカルのWindows PC上のEclipse IDE for Java Developers


LinkedInポーリングでEclipseをお気に入りJava IDEとして最高レートを取得したため、ここでEclipseを使用しています。幸いにも私のお気に入りです。他のIDEでの構成はよく似ている必要があります。



データベース側

データベース・サービスの作成


次のようにカスタム・データベース・サービスを作成します。

[oracle@racnode1 ~]$ srvctl add service -db RACCDB_fra -pdb MOVIEDB -service acsrv -preferred RACCDB1,RACCDB2 -stopoption IMMEDIATE -replay_init_time 600 -retention 86400 -drain_timeout 10 -notification TRUE -commit_outcome TRUE -failover_restore LEVEL1 -failovertype TRANSACTION
 
[oracle@racnode1 ~]$ srvctl start service -db RACCDB_fra -service acsrv
 
[oracle@racnode1 ~]$ srvctl status service -db RACCDB_fra -service acsrv
Service acsrv is running on instance(s) RACCDB1,RACCDB2


アプリケーション・コンティニュイティは、-failover_restore LEVEL1 -failovertype TRANSACTIONによって有効になります。


データベース・ユーザーの作成


ユーザーおよびテスト用の単純な表を作成します。

[oracle@racnode1 ~]$ sqlplus / as sysdba
 
SQL> alter session set container=moviedb;
Session altered.
 
SQL> create user acusr identified by VerySecretPW__2023 quota unlimited on users;
User created.
 
SQL> grant connect to acusr;
Grant succeeded.
 
SQL> create table acusr.actab (text varchar2(128));
Table created.



高速アプリケーション通知(FAN)の有効化


FANポート(通常は6200)は、データベース側で開く必要があります。



クライアント側では、推奨される接続文字列を使用すると、FANはGrid Infrastructure 12c、Oracle Database 12cおよびOracle Client 12c以降から自動構成されます。次を参照してください。



クライアント側

JDKのインストール


常にJavaを使用している場合は、JDKがすでに使用されているはずです。Javaを初めて使用する場合:


Windowsの場合は、ここで説明するようにインストールに従います。


Linuxの場合は、インストールガイドに従うか、yumを使用できます。

sudo yum install java-11-openjdk


Eclipse IDE for Javaのインストール


お気に入りではなく、試してみたい場合は、こちらからダウンロードできます。


Windowsの場合は、インストール手順に従います。


Linuxの場合、バイナリを解凍して実行します。

tar -zxvf eclipse-java-2022-12-R-linux-gtk-x86_64.tar.gz
chmod 744 eclipse
./eclipse



JDBCおよびUCP .jarライブラリのダウンロード


JDBCおよびUCPのダウンロード・ページから、圧縮されたJDBCドライバ(ojdbc11.jar)およびコンパニオンJarsファイルojdbc11-full.tar.gzをダウンロードします。


zipファイルを抽出し、次のJARファイルをアプリケーションのCLASSPATHに追加します。


  • ons.jar、ojdbc11.jarおよびucp11.jar


Eclipseで、プロジェクト名を右クリックし、「Build Path」、「Configure Build Path...」の順にクリックします。



「Libraries、 Classpath」を選択し、「Add External Jars...」をクリックし、zipファイルを抽出するディレクトリから前述の.jarファイルを選択し、「Apply and Close」をクリックします。




Javaの例


次のコード例を使用して、新しいJavaクラス(AC.java)を作成します。

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;
 
//PoolDataSource
import oracle.jdbc.OracleConnection;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import oracle.ucp.jdbc.PoolDataSource;
 
public class AC {
 
    public static void main(String[] args) {
        usePoolDataSource();
    }
     
    public static void usePoolDataSource() {
        try {          
            //use Universal Connection Pool (UCP)
            PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
            pds.setConnectionFactoryClassName("oracle.jdbc.datasource.impl.OracleDataSource");
            pds.setConnectionPoolName("JDBC_UCP");
            //pds.setInitialPoolSize(10);
            pds.setMinPoolSize(4);
            pds.setMaxPoolSize(20);
             
            //load properties
            String PROP_FILE = "C:\\Users\\SPETRUS\\Documents\\spetrus\\development\\java\\ACproject\\src\\config.properties";
            InputStream propInput = new FileInputStream(PROP_FILE);
            Properties prop = new Properties();
            prop.load(propInput);
             
            //set properties
            System.setProperty("oracle.net.tns_admin", prop.getProperty("tns_admin"));
            pds.setURL("jdbc:oracle:thin:@"+prop.getProperty("tns_alias"));
            pds.setUser(prop.getProperty("db_user"));
            pds.setPassword(prop.getProperty("db_password"));
             
            //enable FAN and connection tests
            pds.setConnectionWaitTimeout(3);
            pds.setFastConnectionFailoverEnabled(true);
            pds.setValidateConnectionOnBorrow(true);
             
            //disable auto-commit
            pds.setConnectionProperty(OracleConnection.CONNECTION_PROPERTY_AUTOCOMMIT, "false");
            pds.setConnectionProperty(OracleConnection.CONNECTION_PROPERTY_IMPLICIT_STATEMENT_CACHE_SIZE, "100");
             
            //get connection from the pool
            Connection conn = pds.getConnection();
            //conn.beginRequest(); //not needed, as connection pool sets explicit begin request boundary at getConnection()
            conn.setAutoCommit(false);
             
            //execute query
            Statement stmt = conn.createStatement();                               
            String insert = "insert into acusr.actab values ('Using Application Continuity')";
            int result = stmt.executeUpdate(insert);
            System.out.println("insert result is: " + result); 
            //stop here in bedug mode & (relocate | switchover | terminate the session)
            conn.commit();
            //conn.endRequest(); //not needed, as connection pool sets explicit end request boundary at close()
            conn.close();
            conn=null;         
        }
        catch (Exception e) {
            e.printStackTrace();
        
    }
}


この場合、config.propertiesファイルには、次の値が含まれます。

tns_admin=C:\\Users\\SPETRUS\\Documents\\spetrus\\development
tns_alias=acsrv
db_user=acusr
db_password=VerySecretPW__2023

テストでは、プロパティ・ファイルを使用するのではなく、値をコードに直接配置することもできます。


接続文字列


TNS_ADMINディレクトリのtnsnames.oraファイルで、次の推奨される接続文字列を使用します。

ACSRV = (DESCRIPTION =
(CONNECT_TIMEOUT=90)(RETRY_COUNT=50)(RETRY_DELAY=3)(TRANSPORT_CONNECT_TIMEOUT=3)
    (ADDRESS_LIST =
        (LOAD_BALANCE=ON)
        (ADDRESS = (PROTOCOL = TCP)(HOST=racnode-scan.subnetpublic.vcnfra.oraclevcn.com)(PORT=1521)))
(CONNECT_DATA=(SERVICE_NAME = acsrv.subnetpublic.vcnfra.oraclevcn.com)))


SCANがクライアントから解決できず、テストにパブリック・ホストIPを使用している場合は、ADDRESS_LISTに別のADRESSを追加します:

ACSRV = (DESCRIPTION =
(CONNECT_TIMEOUT=90)(RETRY_COUNT=50)(RETRY_DELAY=3)(TRANSPORT_CONNECT_TIMEOUT=3)
    (ADDRESS_LIST =
        (LOAD_BALANCE=ON)
        (ADDRESS = (PROTOCOL = TCP)(HOST = 130.61.216.103)(PORT = 1521))
        (ADDRESS = (PROTOCOL = TCP)(HOST = 130.61.217.251)(PORT = 1521)))
(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME = acsrv.subnetpublic.vcnfra.oraclevcn.com)))



テスト時間


コミットが実行される前とリクエストの終了前に、2つのブレーク・ポイントを設定します。



デバッグ・モードで実行:



コミットが実行される前にプログラムが停止します。



この時点で、データベースにログインし、ユーザーACUSRの既存のセッションを問い合せます。

set lines 300
col username for a10
col service_name for a20
SQL> select username, sid, serial#, inst_id, service_name from gv$session where username = 'ACUSR';


ユーザーはインスタンス#1に接続しています:



次に、インスタンス#1でサービスを停止します:

[oracle@racnode1 ~]$ srvctl stop service -db  RACCDB_fra -service acsrv -instance RACCDB1 -drain_timeout 10
[oracle@racnode1 ~]$ srvctl status service -db  RACCDB_fra -service acsrv




サービスで指定されたドレイン・タイムアウト(この場合は10秒)が経過するまで待機し、gv$sessionを再度問い合せます:



Eclipseに戻り、実行を再開します。



実行は続行され、次のブレーク・ポイントで停止します。


最も重要なことは、サービスが停止したにもかかわらず、アプリケーションはエラー・メッセージを表示せずに継続したことです。



gv$sessionを問い合せるデータベースに戻ると、ユーザーがインスタンス#2に接続されたことがわかります。



アプリケーションを中断せずにコミットが正常に完了しました:





まとめ



Oracle Application Continuityは、使用可能なデータベース・インスタンス上で処理中のトランザクションをリプレイすることで、エンド・ユーザーからデータベースの中断を隠します。エンド・ユーザーに対しては完全に透過的で、アプリケーション・コードの変更は不要です。


提供されているJavaコードは、JavaでOracle Application Continuityの使用を開始する例です。本番実装の場合は、Oracleのドキュメントに記載されている手順と推奨事項に従ってください。


追加情報

コメント

このブログの人気の投稿

Oracle APEXのInteractive Gridで、Oracle Formsと比較して、重複行の検証を制御/通過させる方法 (2022/07/21)

Oracle APEX 24.1の一般提供の発表 (2024/06/17)

Oracle Cloudのデータベースをオブジェクト・ストレージにバックアップする3つの方法 (2021/12/13)