深入详解Oracle data change notification

简介: 深入详解 Oracle data change notification

0、什么是 Oracle  data change notification  ?

      当有多个应用程序或者进程操作同一个数据库时,其中进程1对Oracle中的某个表Table1进行插入、删除、修改等操作,进程2想在第一个进程操作完成后进行相应的操作。有没有什么方法让进程2获取到进程1的操作?
      类似进程、多线程的同步机制,或者消息响应机制。在Oracle中也有类似的实现,该机制名称即为:data change notification。
      Database Change Notification的作用就是:当数据库中的数据发生变化的时候,自动发出一个通知。

1、支持Oracle版本

Oracle 10gR2 或者以上版本。

2、  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
 用Database Change Notification有三个步骤:

     1)注册: 指定数据库要监听的查询。数据库可以监听DML(Data Manipulation Language)事件,DDL(Data Definition Language)事件,和global 事件(例如关闭数据库)。

  2)通知:一旦数据库中的数据发生变化,数据库将自动发出通知,我们要在我们的程序中定义事件处理操作。

  3)响应:在我们的程序中,一旦收到通知,我们一般情况下会自动更新data cache,当然我们可以通知用户数据发生改变,由他来决定是否进行更新。

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/391054125
http://stackoverflow.com/questions/30847188/when-use-change-notification-interface-the-ora-24912-listener-thread-failed-l

截止2015-6-16,根本原因还没有找到,即该Demo未测试成功。
2015-6-23,发现错误原因:和代码中通过putenv()设置有关,不使用putenv(),改成直接将文件、库包含到工程中,该Bug便不存在。

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 usr@db...\n\n");
//1.连接 第一个参数格式:【IP:端口/服务名】,第二个参数:登录用户名,第三个参数:密码。
con = OCI_ConnectionCreate("100.200.10.50:1521/ts", "tss", "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);
// #endif
 
printf("=> 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效果截图
如下图的三个步骤:

image.png

注意:测试空表insert一条记录的测试情况,需要点下SQLDeveloper右面的“提交”按钮!

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为什么存在,作为程序员还是要抽业余时间追根究底,最终解决掉。


作者:铭毅天下

转载请标明出处,原文地址:http://blog.csdn.net/laoyang360/article/details/46524519

相关文章
|
2月前
|
SQL Oracle 关系型数据库
关系型数据库Oracle Data Guard
【7月更文挑战第11天】
25 1
|
2月前
|
Oracle 关系型数据库 数据库
|
2月前
|
SQL 监控 Oracle
关系型数据库Oracle 的Data Guard:
【7月更文挑战第7天】
33 3
|
10月前
|
Oracle 关系型数据库
Oracle 中data与timstamp互转
Oracle 中data与timstamp互转
|
存储 Oracle Java
[亲测可用]hibernate调用Oracle存储过程|Spring Data JPA调用Oracle存储过程方法
[亲测可用]hibernate调用Oracle存储过程|Spring Data JPA调用Oracle存储过程方法
|
存储 SQL 监控
Oracle BCT(Block Change Tracking)与增量备份---发表在数据和云
BCT(Block Change Tracking)是Oracle从10g开始有的特性。BCT的原理是记录数据文件里每个数据块的变化,并把这些变化信息保存在BCT的跟踪文件中。
385 0
|
运维 Oracle 关系型数据库
【大数据开发运维解决方案】Oracle Data Redaction数据加密测试
最近有个做Java开发的网友问我,怎么在Oracle进行数据加密呢?我给他推荐了Data Redaction。Oracle Database 12c中加入了Data Redaction这个新的安全特性。当然在11g的Database Advanced Security Administrator’s Guide官方文档中就介绍了。
【大数据开发运维解决方案】Oracle Data Redaction数据加密测试
|
机器学习/深度学习 SQL Oracle
深入详解Oracle data change notification
0、什么是 Oracle data change notification ? 当有多个应用程序或者进程操作同一个数据库时,其中进程1对Oracle中的某个表Table1进行插入、删除、修改等操作,进程2想在第一个进程操作完成后进行相应的操作。有没有什么方法让进程2获取到进程1的操作?
432 0
深入详解Oracle data change notification
|
1月前
|
存储 自然语言处理 Oracle
Oracle数据库字符集概述及修改方式
【8月更文挑战第15天】Oracle 数据库字符集定义了数据的编码方案,决定可存储的字符类型及其表示方式。主要作用包括数据存储、检索及跨系统传输时的正确表示。常见字符集如 AL32UTF8 支持多语言,而 WE8MSWIN1252 主用于西欧语言。修改字符集风险高,可能导致数据问题,需事先备份并评估兼容性。可通过 ALTER DATABASE 语句直接修改或采用导出-导入数据的方式进行。完成后应验证数据完整性。此操作复杂,须谨慎处理。
|
1月前
|
数据采集 Oracle 关系型数据库
实时计算 Flink版产品使用问题之怎么实现从Oracle数据库读取多个表并将数据写入到Iceberg表
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。