- 浏览: 20169 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
shanjing:
讲的太细了,没信心看完,我希望知道我调用什么URL来实现Log ...
源代码解读Cas实现单点登出(single sign out)功能实现原理 -
uuuvvv:
明白了,当browser登录cs客户端时,利用cas的代理模式 ...
CAS代理的用途 -
infante_yin:
java.security.cert.CertificateE ...
源代码解读Cas实现单点登出(single sign out)功能实现原理 -
EdwardWorld:
cmd.exe /c echo %NUMBER_OF_PROC ...
(转)Java获得CPU序列号和网卡Mac地址 -
EdwardWorld:
你根本就没有测试,那是获得CPU序列号吗?
(转)Java获得CPU序列号和网卡Mac地址
在一个基于数据库的“实时系统”里面,“实时”获取数据库变化是非常重要的,本文主要描述通过Oracle中的捕获进程实时获取数据库变化。
背景:
要做一个车辆GPS监控系统,主要分两块:
1.采集。由GPS厂商提供实时数据,通过UDP包接收
2.展示。前端程序获取到最新GPS数据后,在地图上模拟车辆的运行情况
备选方案:
1.采集程序接收到UDP包并解析后,将数据放入数据库;前端程序轮询数据库以获取最新数据。
2.采集程序接收到UDP包并解析后,将数据放入数据库,同时向前端程序发送一条消息,传递最新数据。
方案评估:
方案1:最简单,最传统;增加不必要的数据库查询,并且非实时,轮询时间间隔不好确定。
方案2:可实现“实时”,但增加采集程序职责,采集程序本不知道前端系统的存在。
最终方案:
最后采取了另一种方案:通过oracle捕获进程捕获数据库变更(采集程序insert或update一条记录时,捕获进程即时获取到该条记录),将变更记录发送到AQ(oracle高级队列,JMS的oracle实现),前端程序只关注AQ,当有新消息到来时,即刻可收到并做相应处理,反映出实时状态。
关于捕获进程,请参考《Streams概述》,《Streams捕获进程》
实现:
SQL代码
创建表空间和用户:
- Create tablespace streams_tbs datafile 'E:\DBSERVER\ORACLE9I\ORADATA\TESTDB\stream_tbs.dbf' size 25M Reuse autoextend on maxsize unlimited;
- --修改目标表(要捕获变更的表)追加日志
- ALTER TABLE myoracle.TEST_GPS_STATUS ADD SUPPLEMENTAL LOG GROUP log_group_gpsstatus_pk (DEVICEID) ALWAYS;
- create user strmadmin identified by strmadmin default tablespace streams_tbs quota unlimited on streams_tbs;
- grant connect, resource, select_catalog_role to strmadmin;
Create tablespace streams_tbs datafile 'E:\DBSERVER\ORACLE9I\ORADATA\TESTDB\stream_tbs.dbf' size 25M Reuse autoextend on maxsize unlimited; --修改目标表(要捕获变更的表)追加日志 ALTER TABLE myoracle.TEST_GPS_STATUS ADD SUPPLEMENTAL LOG GROUP log_group_gpsstatus_pk (DEVICEID) ALWAYS; create user strmadmin identified by strmadmin default tablespace streams_tbs quota unlimited on streams_tbs; grant connect, resource, select_catalog_role to strmadmin;
授予相应权限
- grant execute on dbms_aqadm to strmadmin;
- grant execute on dbms_capture_adm to strmadmin;
- grant execute on dbms_propagation_adm to strmadmin;
- grant execute on dbms_streams_adm to strmadmin;
- grant execute on dbms_apply_adm to strmadmin;
- grant execute on dbms_flashback to strmadmin;
- grant execute on dbms_aq to strmadmin;
- grant execute on dbms_aqjms to strmadmin;
- grant execute on dbms_aqin to strmadmin;
- grant execute on dbms_aqjms_internal to strmadmin;
grant execute on dbms_aqadm to strmadmin; grant execute on dbms_capture_adm to strmadmin; grant execute on dbms_propagation_adm to strmadmin; grant execute on dbms_streams_adm to strmadmin; grant execute on dbms_apply_adm to strmadmin; grant execute on dbms_flashback to strmadmin; grant execute on dbms_aq to strmadmin; grant execute on dbms_aqjms to strmadmin; grant execute on dbms_aqin to strmadmin; grant execute on dbms_aqjms_internal to strmadmin;
执行系统存储过程分配权限
- BEGIN
- DBMS_RULE_ADM.GRANT_SYSTEM_PRIVILEGE(
- privilege => DBMS_RULE_ADM.CREATE_RULE_SET_OBJ,
- grantee => 'strmadmin',
- grant_option => FALSE);
- END;
- /
- BEGIN
- DBMS_RULE_ADM.GRANT_SYSTEM_PRIVILEGE(
- privilege => DBMS_RULE_ADM.CREATE_RULE_OBJ,
- grantee => 'strmadmin',
- grant_option => FALSE);
- END;
- /
BEGIN DBMS_RULE_ADM.GRANT_SYSTEM_PRIVILEGE( privilege => DBMS_RULE_ADM.CREATE_RULE_SET_OBJ, grantee => 'strmadmin', grant_option => FALSE); END; / BEGIN DBMS_RULE_ADM.GRANT_SYSTEM_PRIVILEGE( privilege => DBMS_RULE_ADM.CREATE_RULE_OBJ, grantee => 'strmadmin', grant_option => FALSE); END; /
以strmadmin帐户登录oracle
创建AQ,类型为JMS消息
- BEGIN
- DBMS_AQADM.CREATE_QUEUE_TABLE(
- Queue_table => 'gpsstatus_queue_table',
- Queue_payload_type => 'SYS.AQ$_JMS_MESSAGE',
- multiple_consumers => false,
- compatible => '8.1.5');
- DBMS_AQADM.CREATE_QUEUE(
- Queue_name => 'gpsstatus_queue',
- Queue_table => 'gpsstatus_queue_table');
- DBMS_AQADM.START_QUEUE(
- queue_name => 'gpsstatus_queue');
- END;
- /
- BEGIN
- DBMS_STREAMS_ADM.SET_UP_QUEUE(
- queue_table => 'gps_temp_queue_table',
- queue_name => 'gps_temp_queue');
- END;
- /
BEGIN DBMS_AQADM.CREATE_QUEUE_TABLE( Queue_table => 'gpsstatus_queue_table', Queue_payload_type => 'SYS.AQ$_JMS_MESSAGE', multiple_consumers => false, compatible => '8.1.5'); DBMS_AQADM.CREATE_QUEUE( Queue_name => 'gpsstatus_queue', Queue_table => 'gpsstatus_queue_table'); DBMS_AQADM.START_QUEUE( queue_name => 'gpsstatus_queue'); END; / BEGIN DBMS_STREAMS_ADM.SET_UP_QUEUE( queue_table => 'gps_temp_queue_table', queue_name => 'gps_temp_queue'); END; /
为目标表创建捕获进程
- BEGIN
- DBMS_STREAMS_ADM.ADD_TABLE_RULES(
- table_name => 'myoracle.TEST_GPS_STATUS',
- streams_type => 'capture',
- streams_name => 'capture_gps',
- queue_name => 'gps_temp_queue',
- include_dml => true,
- include_ddl => false);
- END;
- /
BEGIN DBMS_STREAMS_ADM.ADD_TABLE_RULES( table_name => 'myoracle.TEST_GPS_STATUS', streams_type => 'capture', streams_name => 'capture_gps', queue_name => 'gps_temp_queue', include_dml => true, include_ddl => false); END; /
初始化scn
- DECLARE
- iscn NUMBER; -- Variable to hold instantiation SCN value
- BEGIN
- iscn := DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER();
- DBMS_APPLY_ADM.SET_TABLE_INSTANTIATION_SCN(
- source_object_name => 'myoracle.TEST_GPS_STATUS',
- source_database_name => 'TESTdb',
- instantiation_scn => iscn);
- END;
- /
DECLARE iscn NUMBER; -- Variable to hold instantiation SCN value BEGIN iscn := DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER(); DBMS_APPLY_ADM.SET_TABLE_INSTANTIATION_SCN( source_object_name => 'myoracle.TEST_GPS_STATUS', source_database_name => 'TESTdb', instantiation_scn => iscn); END; /
为消息队列创建代理
- BEGIN
- DBMS_AQADM.CREATE_AQ_AGENT(
- agent_name => 'gpsstatus_agent');
- DBMS_AQADM.ENABLE_DB_ACCESS(
- agent_name => 'gpsstatus_agent',
- db_username => 'strmadmin');
- END;
- /
- DECLARE
- subscriber SYS.AQ$_AGENT;
- BEGIN
- subscriber := SYS.AQ$_AGENT('gpsstatus_agent', NULL, NULL);
- SYS.DBMS_AQADM.ADD_SUBSCRIBER(
- queue_name => 'strmadmin.gpsstatus_queue',
- subscriber => subscriber,
- rule => NULL,
- transformation => NULL);
- END;
- /
BEGIN DBMS_AQADM.CREATE_AQ_AGENT( agent_name => 'gpsstatus_agent'); DBMS_AQADM.ENABLE_DB_ACCESS( agent_name => 'gpsstatus_agent', db_username => 'strmadmin'); END; / DECLARE subscriber SYS.AQ$_AGENT; BEGIN subscriber := SYS.AQ$_AGENT('gpsstatus_agent', NULL, NULL); SYS.DBMS_AQADM.ADD_SUBSCRIBER( queue_name => 'strmadmin.gpsstatus_queue', subscriber => subscriber, rule => NULL, transformation => NULL); END; /
创建存储过程以决定将哪些信息放到消息队列里面
- CREATE OR REPLACE PROCEDURE enq_gps_lcr(in_any IN SYS.ANYDATA) IS
- --agent sys.aq$_agent := sys.aq$_agent('gpsstatus_agent', null, 0);
- message sys.aq$_jms_message;
- enqueue_options dbms_aq.enqueue_options_t;
- message_properties dbms_aq.message_properties_t;
- msgid raw(16);
- lcr SYS.LCR$_ROW_RECORD;
- rc PLS_INTEGER;
- DEVICEID varchar2(11);
- GATHERDATETIME date;
- LONGITUDETYPE char(1);
- LONGITUDEVALUE number ;
- LATITUDETYPE char(1);
- LATITUDEVALUE number ;
- SPEED number ;
- DIRECTION number ;
- BEGIN
- rc := in_any.GETOBJECT(lcr);
- DEVICEID:=lcr.get_value('new','DEVICEID').ACCESSvarchar2();
- GATHERDATETIME := lcr.GET_VALUE('new','GATHERDATETIME').ACCESSdate();
- LONGITUDETYPE := lcr.GET_VALUE('new','LONGITUDETYPE').ACCESSchar();
- LONGITUDEVALUE := lcr.GET_VALUE('new','LONGITUDEVALUE').ACCESSnumber();
- LATITUDETYPE := lcr.GET_VALUE('new','LATITUDETYPE').ACCESSchar();
- LATITUDEVALUE := lcr.GET_VALUE('new','LATITUDEVALUE').ACCESSnumber();
- SPEED := lcr.GET_VALUE('new','SPEED').ACCESSnumber();
- DIRECTION := lcr.GET_VALUE('new','DIRECTION').ACCESSnumber();
- message := sys.aq$_jms_message.construct(1);
- --message.set_replyto(agent);
- message.set_type('');
- message.set_userid('strmadmin');
- message.set_appid('');
- message.set_groupid('');
- message.set_groupseq('');
- message.set_string_property('DEVICEID', DEVICEID);
- message.set_string_property('GATHERDATETIME', to_char(GATHERDATETIME,'yyyy-MM-dd hh24:mi:ss'));
- message.set_string_property('LONGITUDETYPE', LONGITUDETYPE);
- message.set_string_property('LONGITUDEVALUE', to_char(LONGITUDEVALUE) );
- message.set_string_property('LATITUDETYPE', LATITUDETYPE);
- message.set_string_property('LATITUDEVALUE', to_char(LATITUDEVALUE));
- message.set_string_property('SPEED', to_char(SPEED) );
- message.set_string_property('DIRECTION', to_char(DIRECTION) );
- --指定消息生存时间
- message_properties.expiration:=60;
- dbms_aq.enqueue(queue_name => 'strmadmin.gpsstatus_queue',
- enqueue_options => enqueue_options,
- message_properties => message_properties,
- payload => message,
- msgid => msgid);
- COMMIT;
- END;
- /
CREATE OR REPLACE PROCEDURE enq_gps_lcr(in_any IN SYS.ANYDATA) IS --agent sys.aq$_agent := sys.aq$_agent('gpsstatus_agent', null, 0); message sys.aq$_jms_message; enqueue_options dbms_aq.enqueue_options_t; message_properties dbms_aq.message_properties_t; msgid raw(16); lcr SYS.LCR$_ROW_RECORD; rc PLS_INTEGER; DEVICEID varchar2(11); GATHERDATETIME date; LONGITUDETYPE char(1); LONGITUDEVALUE number ; LATITUDETYPE char(1); LATITUDEVALUE number ; SPEED number ; DIRECTION number ; BEGIN rc := in_any.GETOBJECT(lcr); DEVICEID:=lcr.get_value('new','DEVICEID').ACCESSvarchar2(); GATHERDATETIME := lcr.GET_VALUE('new','GATHERDATETIME').ACCESSdate(); LONGITUDETYPE := lcr.GET_VALUE('new','LONGITUDETYPE').ACCESSchar(); LONGITUDEVALUE := lcr.GET_VALUE('new','LONGITUDEVALUE').ACCESSnumber(); LATITUDETYPE := lcr.GET_VALUE('new','LATITUDETYPE').ACCESSchar(); LATITUDEVALUE := lcr.GET_VALUE('new','LATITUDEVALUE').ACCESSnumber(); SPEED := lcr.GET_VALUE('new','SPEED').ACCESSnumber(); DIRECTION := lcr.GET_VALUE('new','DIRECTION').ACCESSnumber(); message := sys.aq$_jms_message.construct(1); --message.set_replyto(agent); message.set_type(''); message.set_userid('strmadmin'); message.set_appid(''); message.set_groupid(''); message.set_groupseq(''); message.set_string_property('DEVICEID', DEVICEID); message.set_string_property('GATHERDATETIME', to_char(GATHERDATETIME,'yyyy-MM-dd hh24:mi:ss')); message.set_string_property('LONGITUDETYPE', LONGITUDETYPE); message.set_string_property('LONGITUDEVALUE', to_char(LONGITUDEVALUE) ); message.set_string_property('LATITUDETYPE', LATITUDETYPE); message.set_string_property('LATITUDEVALUE', to_char(LATITUDEVALUE)); message.set_string_property('SPEED', to_char(SPEED) ); message.set_string_property('DIRECTION', to_char(DIRECTION) ); --指定消息生存时间 message_properties.expiration:=60; dbms_aq.enqueue(queue_name => 'strmadmin.gpsstatus_queue', enqueue_options => enqueue_options, message_properties => message_properties, payload => message, msgid => msgid); COMMIT; END; /
为目标表配置处理器
- BEGIN
- DBMS_APPLY_ADM.SET_DML_HANDLER(
- object_name => 'myoracle.TEST_GPS_STATUS',
- object_type => 'TABLE',
- operation_name => 'UPDATE', --可配置为insert,update,delete等
- error_handler => false,
- user_procedure => 'strmadmin.enq_gps_lcr',
- apply_database_link => NULL);
- END;
- /
BEGIN DBMS_APPLY_ADM.SET_DML_HANDLER( object_name => 'myoracle.TEST_GPS_STATUS', object_type => 'TABLE', operation_name => 'UPDATE', --可配置为insert,update,delete等 error_handler => false, user_procedure => 'strmadmin.enq_gps_lcr', apply_database_link => NULL); END; /
设定参数及启动捕获进程
- BEGIN
- DBMS_STREAMS_ADM.ADD_TABLE_RULES(
- table_name => 'myoracle.TEST_GPS_STATUS',
- streams_type => 'apply',
- streams_name => 'apply_gps',
- queue_name => 'strmadmin.gps_temp_queue',
- include_dml => true,
- include_ddl => false,
- source_database => 'TESTdb');
- END;
- /
- BEGIN
- DBMS_APPLY_ADM.SET_PARAMETER(
- apply_name => 'apply_gps',
- parameter => 'disable_on_error',
- value => 'n');
- END;
- /
- BEGIN
- DBMS_APPLY_ADM.START_APPLY(
- apply_name => 'apply_gps');
- END;
- /
- BEGIN
- DBMS_CAPTURE_ADM.START_CAPTURE(
- capture_name => 'capture_gps');
- END;
- /
BEGIN DBMS_STREAMS_ADM.ADD_TABLE_RULES( table_name => 'myoracle.TEST_GPS_STATUS', streams_type => 'apply', streams_name => 'apply_gps', queue_name => 'strmadmin.gps_temp_queue', include_dml => true, include_ddl => false, source_database => 'TESTdb'); END; / BEGIN DBMS_APPLY_ADM.SET_PARAMETER( apply_name => 'apply_gps', parameter => 'disable_on_error', value => 'n'); END; / BEGIN DBMS_APPLY_ADM.START_APPLY( apply_name => 'apply_gps'); END; / BEGIN DBMS_CAPTURE_ADM.START_CAPTURE( capture_name => 'capture_gps'); END; /
至此,捕获进程配置完毕
可update一条myoracle.TEST_GPS_STATUS 中的记录,再查询gpsstatus_queue_table中是否有对应的一条记录。如果有,则配置成功。
下面是java处理代码,可直接使用JMS接口
本例使用oracle提供的API
- QueueConnectionFactory queueConnectionFactory = null;
- QueueConnection queueConnection = null;
- QueueSession queueSession = null;
- Queue queue = null;
- QueueReceiver subscriber = null;
- Message message = null;
QueueConnectionFactory queueConnectionFactory = null; QueueConnection queueConnection = null; QueueSession queueSession = null; Queue queue = null; QueueReceiver subscriber = null; Message message = null;
- log.info("开始连接 ");
- queueConnectionFactory = AQjmsFactory.getQueueConnectionFactory(ip,sid, port, "thin");
- queueConnection = queueConnectionFactory.createQueueConnection(userName, password);
- log.info("创建Queue Connection 成功");
- queueConnection.start();
- log.info("connection started");
- queueSession = queueConnection.createQueueSession(false,
- Session.AUTO_ACKNOWLEDGE);
- .info("Queue session created");
- queue = ((AQjmsSession) queueSession).getQueue(userName, queueName);
- log.info("Queue getted");
- subscriber = queueSession.createReceiver(queue);
- log.info("初始化完成");
log.info("开始连接 "); queueConnectionFactory = AQjmsFactory.getQueueConnectionFactory(ip,sid, port, "thin"); queueConnection = queueConnectionFactory.createQueueConnection(userName, password); log.info("创建Queue Connection 成功"); queueConnection.start(); log.info("connection started"); queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); .info("Queue session created"); queue = ((AQjmsSession) queueSession).getQueue(userName, queueName); log.info("Queue getted"); subscriber = queueSession.createReceiver(queue); log.info("初始化完成");
开始取消息,本例采取while(true)的方式获取消息。当没有消息的时候,线程会一直阻塞,直到有新的消息到来,立即取出。
while (true) { message = subscriber.receive();//receive方法使没有新消息时,线程挂起 //do something... }
最后:
本文只是试图探求一种比较好的获取实时数据方法,并不适用于所有场合,但在处理实时告警,订单等方面,应该是有一定的用武之地,若结合comet等技术,完全可以实现真正的实时。
如有错误或有更好的处理方式,还请多指教。
相关推荐
以及基于日志的CDC,如Debezium、Canal和Flink-CDC,后者通过解析数据库的日志来实时获取变更。Flink-CDC因其全增量一体化同步、分布式架构和强大的数据加工能力而备受青睐。 **二、为何使用CDC及适用场景** 随着...
在Oracle数据库环境中,实现Socket监听数据库推送信息是一种实时获取数据变化的方法。这通常涉及到数据库触发器、存储过程以及Java编程的结合使用。以下是对这个主题的详细解释: 1. **Oracle触发器**: - 触发器...
1. **配置Oracle CDC连接器**:Flink提供了JDBC connector,它可以配合第三方库如Oracle GoldenGate或Oracle LogMiner来获取Oracle CDC事件。你需要确保已安装了相应的Oracle JDBC驱动(如ojdbc.jar),并将该驱动...
- **研究方法**:首先使用ADO控件获取Oracle数据库中的数据集,然后通过调用TClientDataSet的`SaveToFile()`方法将其保存为指定格式的文件。这里选择XML格式进行保存。 - **示例**:以一个Oracle表`D_PORT`为例,...
Oracle GoldenGate 是一款高效的数据复制解决方案,主要用于实时数据同步和数据迁移。在Oracle数据库环境中,它提供了低延迟、高可用性的数据复制功能。本压缩包"Oracle_GoldenGate_11.2.1.0.3 for Oracle_11g_...
1. `elasticsearch-river-jdbc-1.4.0.10.jar`:这是Elasticsearch JDBC River插件的一个版本,它允许Elasticsearch从各种支持JDBC(Java Database Connectivity)的数据库中获取数据,包括Oracle。River是Elastic...
Oracle公司是Java的主要维护者,它不仅提供了Java开发工具包(JDK),还管理着Java平台标准版(Java SE)、企业版(Java EE)和微型版(Java ME)。SVN,全称Subversion,是一种版本控制系统,用于跟踪文件和目录的...
7. **参与用户组和其他资源**:加入Oracle用户组,利用社区资源,可以获取最新的技术动态和解决方案。 8. **建立标准和变更控制流程**:标准化数据库设计和管理流程,实施严格的变更控制,减少错误和风险。 9. **...
- 包括共享池、大型池、Java池、数据库缓冲区缓存和重做日志缓冲区等。 - 相较于数据库实例的SGA,ASM实例的SGA规模较小。 - **后台进程** - 处理与存储管理相关的任务,如数据同步、元数据维护等。 2. **安装...
- `syschange_on_install--`: 这可能是Oracle安装过程中某个步骤的命令或提示信息,用于记录安装过程中的某些变更。 - `systemmanager--PLSQLDeveloper`: “systemmanager”可能是指Oracle系统管理员账户,“PLSQL...
标题 "idea+springboot+oracle+mybatis" 暗示了这个项目是基于IntelliJ IDEA的一个集成开发环境,使用Spring Boot框架,配合Oracle数据库和MyBatis持久层框架来构建的应用。以下是对这些技术栈的详细解释: 1. **...
Oracle® Fusion Middleware Tutorial for Oracle Coherence 12c (12.1.2) 是为开发者和架构师准备的教程文档,提供了创建、配置和部署基于Oracle Coherence的Java应用的逐步实例。该教程的主要内容包括但不限于以下...
Oracle CDC(Change Data Capture)是一种高效的数据同步技术,主要用于在异构环境中实现实时数据捕捉、转换及传递。它通过监控数据库的日志文件来检测数据变化,并将这些变化数据进行捕获、记录和传输。此技术对于...
首先,关于数据库的设计与操作,Java项目通常会用到关系型数据库管理系统,如MySQL或Oracle。在这个过程中,我们需要学习SQL语言进行数据操作,包括创建表、插入数据、查询和更新等。此外,还会涉及数据库优化、事务...
### Oracle E-Business Suite Release Notes ...因此,在部署或升级Oracle E-Business Suite时,务必检查最新的官方文档以获取最新支持信息。此外,根据实际使用场景选择合适的操作系统版本和浏览器类型也非常重要。
通过监听数据库,可以实现实时的数据变更通知、事务处理、审计日志记录等功能,从而增强应用程序的健壮性和安全性。 ### `AbstractDAO`类分析 `AbstractDAO`类是Java中实现数据库操作的一个典型抽象类设计。它提供...
通过监听和解析MySQL的Binlog事件,我们可以获取到数据库的实时变更信息,进而实现增量数据的捕获。常见的开源工具如Canal、Maxwell等,就是基于此原理实现的。 在“springboot-binlog-main”这个项目中,很可能...
5. **监听和事件驱动**:一些数据库如MySQL的Binlog或Oracle的GoldenGate支持监听数据库日志,当有变更时触发事件,Java应用通过订阅这些事件来同步数据。 6. **第三方库**:如Flyway、Liquibase用于数据库版本管理...
JDBC是Sun Microsystems(现已被Oracle收购)推出的一种Java数据库连接规范,它提供了一种统一的API,让Java程序员能够在不同的数据库系统上编写数据库应用,无需关心底层数据库的差异。 8.0.25是该驱动的版本号,...