适用于:
JDBC - 版本 10.1.0.2 到 11.2.0.3.0 [发行版 10.1 到 11.2]
本文档所含信息适用于所有平台
***Checked for relevance on 24-Apr-2013***
文档 ID 1602113.1
用途
本文档旨在解释两个 RAC 概念,即透明应用程序故障转移 (TAF) 和快速连接故障转移 (FCF)。
适用范围
需要了解 JDBC。
详细信息
透明应用程序故障转移 (TAF)
-
TAF 的含义是什么?
透明应用程序故障转移 (TAF),简称应用程序故障转移,是 OCI 驱动程序的一项功能。当连接到的数据库实例出错时,可利用该功能自动重新连接该数据库。此时,活动事务将回滚。事务回滚将恢复上次提交的事务。无论之前的连接是如何被丧失的,这个新的数据库连接将由另一个节点创建,但与原始连接是完全一样的。
TAF 总处于活动状态而无需设置。
TAF 不能用于 thin 驱动程序。
-
TAF 的确切用途是什么?
当第一个实例出错时,可以通过 TAF 自动转移到其他实例。
有关 OCI 和 TAF 的更多详细信息,请参阅 Oracle? Call Interface Programmer's Guide.
-
如何将 TAF 用于 JDBC 驱动程序?
需在 tnsnames.ora 中设置以下服务:
inst_primary=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(Host=hostname1)(Port=1521)) (ADDRESS = (PROTOCOL = TCP)(HOST=hostname2)(PORT = 1521))
(CONNECT_DATA=(SERVICE_NAME=ORCL)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC))))
请参阅 Oracle? Database Net Services Administrator's Guide 中Configuring Transparent Application Failover 这一节,了解有关 failover_mode 的更多详细信息。
故障转移类型事件
以下是 OracleOCI 故障转移接口中可能的故障转移类型:
-
FO_SESSION
相当于 tnsnames.ora 文件 CONNECT_DATA 标志中的 FAILOVER_MODE=SESSION。其含义是,当 OCI 应用程序中的打开游标需要重新执行时,服务器端仅需重新验证用户会话。
-
FO_SELECT
相当于 tnsnames.ora 文件 CONNECT_DATA 标志中的 FAILOVER_MODE=SELECT。其含义是,服务器端需重新验证用户会话,而且 OCI 中的打开游标可继续获取。这意味着客户机端逻辑维持每个打开游标的获取状态。
-
FO_NONE
相当于 tnsnames.ora 文件 CONNECT_DATA 标志中的 FAILOVER_MODE=NONE。这是默认设置,不使用故障转移功能。还可明确指定阻止故障转移的发生。另外,FO_TYPE_UNKNOWN 意味着从 OCI 驱动程序返回了一个错误的故障转移类型。
以下是 OracleOCI 故障转移接口中可能的故障转移事件:
-
FO_BEGIN
说明故障转移已检测到一个丢失的连接,故障转移开始启动。
-
FO_END
说明成功完成故障转移。
-
FO_ABORT
说明故障转移不成功,没有重试选项。
-
FO_REAUTH
说明已重新验证用户句柄。
-
FO_ERROR
说明故障转移暂不成功,但为应用程序提供处理错误并重试故障转移的机会。处理错误的常规方法是发出 sleep() 方法,并通过返回值 FO_RETRY 进行重试。
-
FO_RETRY
说明应用程序应重试故障转移。
-
FO_EVENT_UNKNOWN
一个错误的故障转移事件。
TAF 回调
当一个数据库连接故障,故障转移至另一个数据库连接时使用 TAF 回调。TAF 回调是故障转移时注册的回调。故障转移时调用回调,将生成的事件通知 JDBC 应用程序。应用程序也有一些故障转移控制。
-
TAF 回调记录在 Oracle? Database JDBC Developer's Guide 的以下章节:TAF Callbacks
注意:回调设置是可选的。
Java TAF 回调接口
OracleOCI 故障转移接口包括 callbackFn() 方法,该方法支持以下类型和事件:
public interface OracleOCIFailover{
// Possible Failover Types
public static final int FO_SESSION = 1;
public static final int FO_SELECT = 2;
public static final int FO_NONE = 3;
public static final int;
// Possible Failover events registered with callback
public static final int FO_BEGIN = 1;
public static final int FO_END = 2;
public static final int FO_ABORT = 3;
public static final int FO_REAUTH = 4;
public static final int FO_ERROR = 5;
public static final int FO_RETRY = 6;
public static final int FO_EVENT_UNKNOWN = 7;
public int callbackFn (Connection conn,
Object ctxt, // ANy thing the user wants to save
int type, // One of the possible Failover Types
int event ); // One of the possible Failover Events
-
用于测试 TAF 的示例代码
请参阅以下 TAF 示例,它来自于 OTN 上提供的 JDBC 标准示例。
/*
* This sample demonstrates the registration and operation of
* JDBC OCI application failover callbacks
*
* Note: Before you run this sample, set up the following
* service in tnsnames.ora:
* inst_primary=(DESCRIPTION=
* (ADDRESS=(PROTOCOL=tcp)(Host=hostname)(Port=1521))
* (CONNECT_DATA=(SERVICE_NAME=ORCL)
* (FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC))
* )
* )
* Please see Net8 Administrator's Guide for more detail about
* failover_mode
*
* To demonstrate the the functionality, first compile and start up the sample,
* then log into sqlplus and connect /as sysdba. While the sample is still
* running, shutdown the database with "shutdown abort;". At this moment,
* the failover callback functions should be invoked. Now, the database can
* be restarted, and the interrupted query will be continued.
*
*/
// You need to import java.sql and oracle.jdbc packages to use
// JDBC OCI failover callback
import java.sql.*;
import java.net.*;
import java.io.*;
import java.util.*;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleOCIFailover;
import oracle.jdbc.pool.OracleDataSource;
public class OCIFailOver {
static final String user = "hr";
static final String password = "hr";
static final String URL = "jdbc:oracle:oci8:@inst_primary";
public static void main (String[] args) throws Exception {
Connection conn = null;
CallBack fcbk= new CallBack();
String msg = null;
Statement stmt = null;
ResultSet rset = null;
// Create a OracleDataSource instance and set properties
OracleDataSource ods = new OracleDataSource();
ods.setUser(user);
ods.setPassword(password);
ods.setURL(URL);
// Connect to the database
conn = ods.getConnection();
// register TAF callback function
((OracleConnection) conn).registerTAFCallback(fcbk, msg);
// Create a Statement
stmt = conn.createStatement ();
for (int i=0; i<30; i++) {
// Select the NAMEs column from the EMPLOYEES table
rset = stmt.executeQuery ("select FIRST_NAME, LAST_NAME from EMPLOYEES");
// Iterate through the result and print the employee names
while (rset.next ())
System.out.println (rset.getString (1) + " " +
rset.getString (2));
// Sleep one second to make it possible to shutdown the DB.
Thread.sleep(1000);
} // End for
// Close the RseultSet
rset.close();
// Close the Statement
stmt.close();
// Close the connection
conn.close();
} // End Main()
} // End class jdemofo
/*
* Define class CallBack
*/
class CallBack implements OracleOCIFailover {
// TAF callback function
public int callbackFn (Connection conn, Object ctxt, int type, int event) {
/*********************************************************************
* There are 7 possible failover event
* FO_BEGIN = 1 indicates that failover has detected a
* lost connection and faiover is starting.
* FO_END = 2 indicates successful completion of failover.
* FO_ABORt = 3 indicates that failover was unsuccessful,
* and there is no option of retrying.
* FO_REAUTH = 4 indicates that a user handle has been re-
* authenticated.
* FO_ERROR = 5 indicates that failover was temporarily un-
* successful, but it gives the apps the opportunity
* to handle the error and retry failover.
* The usual method of error handling is to issue
* sleep() and retry by returning the value FO_RETRY
* FO_RETRY = 6
* FO_EVENT_UNKNOWN = 7 It is a bad failover event
*********************************************************************/
String failover_type = null;
switch (type) {
case FO_SESSION:
failover_type = "SESSION";
break;
case FO_SELECT:
failover_type = "SELECT";
break;
default:
failover_type = "NONE";
}
switch (event) {
case FO_BEGIN:
System.out.println(ctxt + ": "+ failover_type + " failing over...");
break;
case FO_END:
System.out.println(ctxt + ": failover ended");
break;
case FO_ABORT:
System.out.println(ctxt + ": failover aborted.");
break;
case FO_REAUTH:
System.out.println(ctxt + ": failover.");
break;
case FO_ERROR:
System.out.println(ctxt + ": failover error gotten. Sleeping...");
// Sleep for a while
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
System.out.println("Thread.sleep has problem: " + e.toString());
}
return FO_RETRY;
default:
System.out.println(ctxt + ": bad failover event.");
break;
}
return 0;
}
}
快速连接故障转移 (FCF)
-
FCF 的含义是什么?
快速连接故障转移为 JDBC 应用程序提供一种与驱动程序无关的方法以利用 10g Release 1 (10.1) 中引入的连接故障转移工具。
当 RAC 服务故障传播到 JDBC 应用程序时,数据库已回滚本地事务。然后,缓存管理器会清空所有无效连接。当一个拥有无效连接的应用程序尝试通过该连接进行工作时,将收到 SQLException ORA-17008, Closed Connection异常。该应用程序有必要处理该异常并重新连接。
-
FCF 的确切用途是什么?
FCF 提供故障的快速通知,并可使用相同 URL 立刻重新连接。当 RAC 节点失败时,应用程序将收到一个异常。该应用程序有必要处理该异常并重新连接。
JDBC 驱动程序不会重新瞄准现有连接。当节点失败时,应用程序必须关闭现有连接并获取一个新连接。应用程序通过获取异常来了解节点失败。当节点失败时不止抛出一个 ORA 异常,应用程序必须能处理所有这些错误。
应用程序可能会调用 OracleConnectionCacheManager 上的 isFatalConnectionError() API 来决定所捕获的 SQLException 是否致命。
如果该 API 的返回值为 true,则需重试 DataSource.xxxxxx 上的 getConnection
-
如何将 FCF 用于 JDBC 驱动程序?
若要将 FCF 用于 JDBC,必须完成以下操作:
-
配置并启动 ONS。如果 ONS 未正确设置,则隐式连接缓存创建将失败,并会针对第一个 getConnection() 请求抛出 ONSException。
请参阅 Oracle? Universal Connection Pool for JDBC Developer's Guide 中的Configuring ONS一节,该节位于 Using Fast Connection Failover
-
FCF 目前通过一个启用池的数据源进行配置,并与 UCP 紧密集成。正如在 10g 和 11g R1 中使用的那样,通过隐式连接缓存启用的 FCF 目前已被弃用。
-
在向 OracleDataSource 发送第一条 getConnection() 请求前设置 FastConnectionFailoverEnabled 属性。当启用 FastConnection 故障转移时,故障转移适用于池中所有连接。
-
设置 OracleDataSource url 属性时,请使用服务名而非 SID。
-
用于测试 FCF 的示例代码
以下代码示例显示了 FCF 的工作方法,它可能并非最佳方法,但给出了所需操作的一般思路。
请确保更改程序、、 和 中的以下字符串。
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionPoolName("FCFSamplePool");
pds.setFastConnectionFailoverEnabled(true);
pds.setONSConfiguration("nodes=racnode1:4200,racnode2:4200\nwalletfile= /oracle11/onswalletfile");
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");pds.setURL("jdbc:oracle:thin@(DESCRIPTION= "+
"(LOAD_BALANCE=on)"+
"(ADDRESS=(PROTOCOL=TCP)(HOST=racnode1) (PORT=1521))"+
"(ADDRESS=(PROTOCOL=TCP)(HOST=racnode2) (PORT=1521))"+
"(CONNECT_DATA=(SERVICE_NAME=service_name)))");
...
try { conn = pds.getConnection; ...}catch (SQLException sqlexc)
{
if (conn == null || !((ValidConnection) conn).isValid())
// take the appropriate action
...
conn.close();
}
上述示例从 Oracle? Universal Connection Pool for JDBC Developer's Guide 11g Release 2 (11.2) 中的 8 Using Oracle RAC Features 这一节的 FCF 文档摘录。
基于 ICC 的 FCF 仍记录在 Oracle? Database JDBC Developer's Guide 11g Release 2 (11.2) section 27 Fast Connection Failover 中,然而,本章目前已标记为弃用。
建议使用基于 UCP 的 FCF 实施。
示例请参阅 Note 566573.1 Fast Connection Failover (FCF) Test Client Using 11g JDBC Driver and 11g RAC Cluster
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/13750068/viewspace-1384662/
,如需转载,请注明出处,否则将追究法律责任。