你的Oracle 12C Transaction Guard已到賬
前 言
前篇講到TAF各種故障切換場景,
溫故通道:《抬頭MOS看文獻,埋頭機房做實驗》
但是對於事務來說,發生異常宕機,應用程序無法感知事務當前狀態,很容易發生多次提交等不可控情況,transaction guard事務衛士因此而生。
什麼是transaction guard事務衛士?
Oracle 12c Transaction Guard是TAF的下一個發展,它涵蓋了TAF的一些限制,例如使用OCI。
Transaction Guard為應用程序提供了一個通用工具,在發生計劃內和計劃外停機還有重複提交時用於」最多執行一次」(保持事務一致性),
應用程序使用稱為邏輯事務ID(LTXID)的新概念來確定停機後資料庫會話中打開的最後一個事務的結果。
如果不使用Transaction Guard,嘗試在中斷後重試操作的應用程序可能會通過提交重複事務來導致邏輯損壞。
簡單說來:
當我們進行故障檢測和故障恢復的時候,需要考慮一個問題:資料庫到應用的響應是很短暫的,因此在實例發生問題時,commit的響應可能會丟失,比如程序做了dml操作,並向db發出commit提交請求。
如果此時實例故障,應用程序沒有從資料庫那裡得到任何反饋響應,此時應用不知道事務狀態,會發生什麼情況?
可能會發生的2種情況!
1.資料庫後台提交了修改,但前台應用程序未收到成功的資料庫後台提交了修改,但前台應用程序未收到成功的反饋響應反饋響應
2.在成功提交操作之前,資料庫已經出現故障了,所以應用程序必須重新運行並提交
這兩種情況下,應用程序都必須知道事務的狀態以避免資料庫損壞。TG孕育而生,其提供了一種機制來跟蹤交易狀態,甚至可以在資料庫出現故障之後進行跟蹤。
Transaction Guard原理是什麼?
TG引入邏輯標識ID(LTXID)的概念,對於資料庫連接的會話來說,一個邏輯事務ID是唯一的,並且邏輯事務標識符與資料庫的事務ID相映射。資料庫會跟蹤邏輯事務ID的結果,如果資料庫發生故障,那麼應用程序連接將可以使用LTXID來查詢事務狀態,以此確定事務是否被提交。
Transaction guard是如何工作的?
在標準的提交場景中,資料庫提交一個事務並且得到一個成功的信息返回給客戶端。
在上圖中,客戶端提交了一個commit語句,並收到一個通信失敗的消息,這類錯誤可能有很多種原因,比如實例宕了,網路通信失敗等,在這個場景下,客戶端是不知道事務狀態的。
通信失敗後,資料庫可能仍在運行提交,並且不知道客戶端已斷開連接。檢查事務狀態並不保證活動事務在檢查後是否會提交,如果客戶端因為此過期信息而重新發送提交,那麼資料庫可能會重複該事務,從而導致邏輯損壞。
Logical Transaction ID
資料庫通過使用稱為 logical transaction ID.的全局唯一標識符來解決通信故障,此ID包含會話第一次連接時分配的邏輯會話編號,以及每次會話提交或回滾時更新的正在運行的提交編號,從應用程序的角度來看,邏輯事務ID唯一標識了失敗會話上提交的最後一個資料庫事務。對於一個事務多次往返客戶端伺服器的提交,資料庫始終只保留一個邏輯事務ID。
最多一次協議(at-most-once)通過要求資料庫執行以下操作來啟用對提交結果的訪問:
1 維護同意重試的保留期的邏輯交易ID
2 在提交時保留邏輯事務ID
在應用程序可以確定最後一個事務發生可恢復錯誤後的結果之前,應用程序(Java,OCI,OCCI或ODP.Net API)可以獲取客戶端保存的邏輯事務ID。應用程序可以使用邏輯事務ID調用PL / SQL過程DBMS_APP_CONT.GET_LTXID_OUTCOME來確定最後提交的結果:提交(true或false)和用戶調用完成(true或false)。
使用Transaction Guard時,當錯誤已經恢復並且最後一個會話的事務未提交,應用程序可以自己控制重新執行事務,應用程序可以在最後一個事務提交並且用戶調用完成時繼續。應用程序可以使用Transaction Guard將已知結果返回給客戶端,以便客戶端可以決定下一個要採取的操作。
Transaction guard事例
在上圖中,資料庫通知應用程序是否提交事務以及是否完成最後一次用戶調用。 應用程序然後可以將結果返回給最終用戶。
可能性如下:
1. 如果事務提交並且用戶調用已完成,則應用程序可以將結果返回給最終用戶並繼續。
2. 如果事務已提交但用戶調用未完成,則應用程序可以將結果返回給最終用戶並發出警告。 示例包括丟失的綁定或丟失的行數。 一些應用程序依賴於額外的信息,而另一些則不需要。
3. 如果用戶調用未提交,則應用程序可以將此信息返回給最終用戶,或安全地重新提交。 該協議是有保證的。 當提交狀態返回false時,最後一次提交被阻止提交。
RAC架構下,TAF和TG的集成
當啟用TAF時,開發人員不得直接使用Transaction Guard。如果TAF已啟用或可啟用,則在為ODP.NET或OCI開發Transaction Guard時,必須使用與「ODP.NET with TAF」中提供的示例類似的代碼。
故障時,12c中的TAF獲取新連接, 並且啟用TG時調用Transaction Guard來強制提交結果。
此行為適用於TAF BASIC和TAF SELECT模式。如果TG返回提交並完成,則TAF將繼續並且應用程序視為沒有發現錯誤。如果TG返回未提交或已提交但未完成,則TAF嚮應用程序返回TAF錯誤。 TAF維護新的連接。
當同時使用TAF和Transaction Guard時,開發人員可以使用TAF錯誤代碼(ORA-25402,ORA-25408,ORA-25405)來決定安全地重新提交事務,或者向用戶返回指示未提交事務的消息。這是最為安全的提交方式。如果只啟用TAF,重新提交或返回未提交是不安全的。
重新提交要求在TAF調用中建立正確的環境,並且整個事務回滾並重新提交。如下例所示,可以使用布爾變數來跟蹤啟用了Transaction Guard。這個變數必須在TAF調用中被使用。
注意:在會話失敗時不會調用TAF(這包括操作系統級別的"kill -9"或更改系統kill會話)。在INSTANCE失敗或NODE DOWN事件和關機時調用TAF,並斷開POST_TRANSACTION。
如下提供ODP.Net的代碼示例。(注意資料庫和客戶端版本都必須在12.1.0.1以上版本)
using System;
using Oracle.DataAccess.Client;
class TransactionGuardSample
{
static void Main()
{
bool bReadyToCommit = false;
// This code is needed to test whether Transaction Guard is enabled.
bool bTGEnabled = false;
string constr = "user id=hr;password=hr;data source=oracle";
OracleConnection con = new OracleConnection(constr);
OracleTransaction txn = null;
OracleCommand cmd = null;
try
{
string sql = " update employees set salary=10000 where employee_id=103";
con.Open();
// This bTGEnabled boolean variable is needed to check whether TG is enabled.
// Set this variable immediately after connecting and again in the TAF callback
bTGEnabled = con.OracleLogicalTransaction != null;
txn = con.BeginTransaction();
cmd = new OracleCommand(con, sql);
cmd.ExecuteNonQuery();
bReadyToCommit = true;
}
catch (Exception ex)
{
// rollback here as the SQL execution is unsuccessful
txn.Rollback();
Console.WriteLine(ex.ToString());
}
try // progress to here as TX is successful
{
if (bReadyToCommit)
txn.Commit();
}
catch (Exception ex)
{
//ONLY handle the listed TAF errors and ONLY when Transaction Guard is enabled
if (bTGEnabled && (ex.Number == 25402 || ex.Number == 25408 || ex.Number == 25405 ))
{
// application may cleanup, then rollback and re-submit the current transaction
}
else
{
// handle the error as before; do not resubmit
}
}
finally
{
// dispose all objects
txn.Dispose();
cmd.Dispose();
con.Dispose(); // place the connection back to the connection pool
}
}
}
那些年,我們一起啃過的文檔:
Transaction Guard (TG) Integration with Transparent Application Failover (TAF) (文檔 ID 2011697.1)
不想走丟的話,請關注公眾號 恒生DBA公社:hs_dba
讓時代更多元,讓工作更高效
TAG:恒生DBA公社 |