標籤:oracle otl data change notifica ora-24912 源碼 實現
深入詳解 Oracle data change notification
1、什麼是 Oracle data change notification ? 當有多個應用程式或者進程操作同一個資料庫時,其中進程1對Oracle中的某個表Table1進行插入、刪除、修改等操作,進程2想在第一個進程操作完成後進行相應的操作。有沒有什麼方法讓進程2擷取到進程1的操作? 類似進程、多線程的同步機制,或者訊息響應機制。在Oracle中也有類似的實現,該機制名稱即為:data change notification。
2、支援Oracle版本Oracle 10gR2 或者以上版本。
3、 data change notification支援的操作 (1) 資料庫狀態變化 Database status changes : startup and shutdown (2) 資料庫物件變化 Database objects changes : 1) DDL changes : alter or drop actions 2) DML changes : insert, delete, update actions
3、兩種使用方法
3.1 OTL data change notification源碼詳解樣本源碼參考資料:【1】http://otl.sourceforge.net/otl4_subscriber.htm【2】http://otl.sourceforge.net/otl4_ex585.htm
使用中在subs.subscribe()介面會出現Bug:bug號及詳情——ORA-24912: Listener thread failed. Listen failed.Google提供的解決方案:The client needs to be restarted。(但測試不湊效)錯誤及詳見我的提問:http://bbs.csdn.net/topics/391054125http://stackoverflow.com/questions/30847188/when-use-change-notification-interface-the-ora-24912-listener-thread-failed-l
截止2015-6-16,根本原因還沒有找到,即該Demo未測試成功。
3.2 ocilib data change notification源碼詳解樣本源碼參考資料:http://orclib.sourceforge.net/doc/html/group___ocilib_c_api_subscriptions.html
//代碼解析(VS2010 C++實現,已經驗證過)
#include "stdafx.h"#include "ocilib.h"#pragma comment (lib, "ociliba.lib")#ifdef _WINDOWS#define sleep(x) Sleep(x*1000)#endif#define wait_for_events() sleep(5000)void event_handler(OCI_Event *event);void error_handler(OCI_Error *err);int main(void){OCI_Connection *con;OCI_Subscription *sub;OCI_Statement *st;printf("=> Initializing OCILIB in event mode...\n\n");//0.第二個參數為原有的oracle的DLL所在的路徑名稱。if (!OCI_Initialize(error_handler, "oracle", OCI_ENV_EVENTS))return EXIT_FAILURE;printf("=> Connecting to [email protected]\n\n");//1.串連 第一個參數格式:【IP:連接埠/服務名】,第二個參數:登入使用者名稱,第三個參數:密碼。con = OCI_ConnectionCreate("100.200.10.50:1521/ts54", "tss54", "psdts**", OCI_SESSION_DEFAULT);OCI_SetAutoCommit(con, TRUE);printf("=> Creating statement...\n\n");st = OCI_StatementCreate(con);printf("=> Creating tables...\n\n");//2.建立資料表OCI_ExecuteStmt(st, "create table table1(code number)");OCI_ExecuteStmt(st, "create table table2(str varchar2(10))");printf("=> Registering subscription...\n\n");//3.註冊通知事件 sub-00 為通知名稱.sub = OCI_SubscriptionRegister(con, "sub-00", OCI_CNT_ALL, event_handler, 5468, 0);printf("=> Adding queries to be notified...\n\n");OCI_Prepare(st, "select * from table1");OCI_SubscriptionAddStatement(sub, st);OCI_Prepare(st, "select * from table2");OCI_SubscriptionAddStatement(sub, st);//等待響應註冊事件wait_for_events(); //可以Sleep足夠時間一直等待,當有其他進程進行修改表的操作,該處就會有響應。// 以下為測試用,可以不用執行。// #if 0// //4.執行對應資料庫alter操作// printf("=> Executing some DDL operation...\n\n");// OCI_ExecuteStmt(st, "alter table table1 add price number"); //alter事件// //等待5s,等待列印輸出.// wait_for_events();// // // //5.執行資料庫的inser,update操作。// printf("=> Executing some DML operation...\n\n");// OCI_ExecuteStmt(st, "insert into table1 values(1, 10.5)");// OCI_ExecuteStmt(st, "insert into table2 values('shoes')");// OCI_ExecuteStmt(st, "update table1 set price = 13.5 where code = 1");// OCI_ExecuteStmt(st, "delete from table2 ");// wait_for_events();// // //6.執行drop資料庫表操作。// printf("=> Droping tables...\n\n");// OCI_ExecuteStmt(st, "drop table table1");// OCI_ExecuteStmt(st, "drop table table2");// wait_for_events();// // printf("=> Disconnecting from DB...\n\n");// OCI_ConnectionFree(con);// printf("=> Stopping the remote database...\n\n");// OCI_DatabaseShutdown("db", "sys", "sys", // OCI_SESSION_SYSDBA,// OCI_DB_SDM_FULL,// OCI_DB_SDF_IMMEDIATE);// #endifprintf("=> Unregistering subscription...\n\n");OCI_SubscriptionUnregister(sub);printf("=> Cleaning up OCILIB resources...\n\n");OCI_Cleanup();printf("=> Done...\n\n");return EXIT_SUCCESS;}void error_handler(OCI_Error *err){int err_type = OCI_ErrorGetType(err);const char *err_msg = OCI_ErrorGetString(err);printf("** %s - %s\n", err_type == OCI_ERR_WARNING ? "Warning" : "Error", err_msg);}void event_handler(OCI_Event *event){unsigned int type = OCI_EventGetType(event);unsigned int op = OCI_EventGetOperation(event);OCI_Subscription *sub = OCI_EventGetSubscription(event);printf("** Notification : %s\n\n", OCI_SubscriptionGetName(sub));printf("...... Database : %s\n", OCI_EventGetDatabase(event));switch (type){case OCI_ENT_STARTUP:printf("...... Event : Startup\n");break;case OCI_ENT_SHUTDOWN:printf("...... Event : Shutdown\n");break;case OCI_ENT_SHUTDOWN_ANY:printf("...... Event : Shutdown any\n");break;case OCI_ENT_DROP_DATABASE:printf("...... Event : drop database\n");break;case OCI_ENT_DEREGISTER:printf("...... Event : deregister\n");break;case OCI_ENT_OBJECT_CHANGED:printf("...... Event : object changed\n");printf("........... Object : %s\n", OCI_EventGetObject(event));switch (op){case OCI_ONT_INSERT:printf("........... Action : insert\n");break;case OCI_ONT_UPDATE:printf("........... Action : update\n");break;case OCI_ONT_DELETE:printf("........... Action : delete\n");break;case OCI_ONT_ALTER:printf("........... Action : alter\n");break;case OCI_ONT_DROP:printf("........... Action : drop\n");break;}if (op < OCI_ONT_ALTER)printf("........... Rowid : %s\n", OCI_EventGetRowid(event));break;}printf("\n");}
//data change notification效果如的三個步驟:
4、兩種思路對比及Bug分析反思周一下午臨危受命,預期周一晚上完成data change notification的驗證。但是最終測試發現有RA-24912: Listener thread failed. Listen failed的Bug。Google及Stackoverflow了N多資料,都沒有解決方案。一直持續到周二下午4點,在OTL嘗試了N多方法都沒有解決。實驗思路包括:1)授權本機使用者具有grant 許可權,即能執行成功“grant change notifiation to 使用者名稱”,已經授權,但Bug依然存在。2)Stackoverflow老外提供思路,可能和服務有關,重啟Oracle資料庫,Bug依然存在。3)從程式subscribe介面分析,但由於第三方介面,沒有在深層列印日誌,沒有理清根本原因。且subscirbe介面為void類型,無返回值,只能通過捕獲異常,得到錯誤。且錯誤資訊就只有監聽失敗。
綜上,既然OTL這條路不通,為何不去嘗試下其他思路。當在Google輸入"oracle data change notification C++" 關鍵詞,便找到了3.2的實現。
反思:1、對於不熟悉的領域,不能“一棵樹上弔死”,當嘗試N久一條路不通, 且業界大牛也沒有好的方案的時候,可以考慮換換思路,說不定會柳暗花明。2、當然,對於第一條路的Bug為什麼存在,作為程式員還是要抽業餘時間追根究底,最終解決掉。
2015-6-16 22:44 思於家中床前
銘毅天下
轉載請標明出處,原文地址:http://blog.csdn.net/laoyang360/article/details/46524519
如果感覺本文對您有協助,請點擊‘頂’支援一下,您的支援是我堅持寫作最大的動力,謝謝!
深入詳解Oracle data change notification