CDC 之 Oracle数据订阅

Java订阅Oracle数据变更的方法

在Java中订阅Oracle数据库的数据变更,主要有以下几种方法:

1. 使用Oracle Advanced Queuing (AQ)

Oracle AQ是Oracle提供的消息队列服务,可以用于发布和订阅数据变更事件。

// 示例代码
import oracle.jdbc.OracleConnection;
import oracle.jdbc.aq.AQFactory;
import oracle.jdbc.aq.AQMessage;
import oracle.jdbc.aq.AQMessageProperties;
import oracle.jdbc.aq.AQQueue;

// 获取数据库连接
Connection conn = DriverManager.getConnection(url, username, password);
OracleConnection oracleConn = conn.unwrap(OracleConnection.class);

// 创建AQ会话
AQFactory aqFactory = AQFactory.getAQFactory(oracleConn);
AQQueue queue = aqFactory.createQueue("YOUR_QUEUE_NAME");
queue.start();

// 订阅消息
while (true) {
    AQMessage message = queue.dequeue();
    // 处理消息内容
    System.out.println("Received message: " + message.getMessage());
}

2. 使用Oracle Change Data Capture (CDC)

CDC可以捕获数据库表的数据变更。

// 使用Oracle JDBC驱动的CDC API
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleStatement;
import oracle.jdbc.dcn.DatabaseChangeEvent;
import oracle.jdbc.dcn.DatabaseChangeListener;
import oracle.jdbc.dcn.DatabaseChangeRegistration;

// 获取数据库连接
Connection conn = DriverManager.getConnection(url, username, password);
OracleConnection oracleConn = conn.unwrap(OracleConnection.class);

// 注册变更通知
Properties prop = new Properties();
prop.setProperty(OracleConnection.DCN_NOTIFY_CHANGEIDS, "true");
DatabaseChangeRegistration dcr = oracleConn.registerDatabaseChangeNotification(prop);

// 添加监听器
dcr.addListener(new DatabaseChangeListener() {
    @Override
    public void onDatabaseChangeNotification(DatabaseChangeEvent event) {
        System.out.println("Received change event: " + event);
        // 处理变更事件
    }
});

// 创建带注册ID的语句
OracleStatement stmt = (OracleStatement) oracleConn.createStatement();
stmt.setDatabaseChangeRegistration(dcr);
ResultSet rs = stmt.executeQuery("SELECT * FROM YOUR_TABLE WHERE ROWNUM < 1");
rs.close();
stmt.close();

3. 使用Oracle XStream (12c及以上版本)

XStream是Oracle的高性能变更数据捕获技术。

// 需要Oracle XStream API
import oracle.jdbc.OracleConnection;
import oracle.stream.XStream;
import oracle.stream.XStreamIn;
import oracle.stream.XStreamInAdapter;

// 获取数据库连接
Connection conn = DriverManager.getConnection(url, username, password);
OracleConnection oracleConn = conn.unwrap(OracleConnection.class);

// 创建XStream实例
XStream xstream = XStreamIn.createXStreamIn(oracleConn, new Properties());

// 设置回调处理器
XStreamInAdapter adapter = new XStreamInAdapter() {
    @Override
    public void receiveLCR(XStreamLCR lcr) {
        // 处理逻辑变更记录
        System.out.println("Received LCR: " + lcr);
    }
};

// 开始接收变更
xstream.start(adapter);

4. 使用第三方框架

Debezium (基于Kafka Connect)

// 配置Debezium Oracle连接器
public class DebeziumOracleConnector {
    public static void main(String[] args) {
        // 创建Kafka Connect配置
        Map<String, String> config = new HashMap<>();
        config.put("connector.class", "io.debezium.connector.oracle.OracleConnector");
        config.put("database.hostname", "oracle-host");
        config.put("database.port", "1521");
        config.put("database.user", "username");
        config.put("database.password", "password");
        config.put("database.dbname", "ORCLCDB");
        config.put("database.pdb.name", "ORCLPDB1");
        config.put("database.server.name", "oracle_server");
        config.put("table.include.list", "SCHEMA.TABLE");
        config.put("database.history.kafka.bootstrap.servers", "kafka:9092");
        config.put("database.history.kafka.topic", "schema-changes");

        // 创建并启动连接器
        try (EmbeddedEngine engine = EmbeddedEngine.create()
                .using(config)
                .notifying(record -> {
                    System.out.println("Key = " + record.key());
                    System.out.println("Value = " + record.value());
                })
                .build()) {
            engine.run();
        }
    }
}

Spring Data + Oracle CDC

@Configuration
public class OracleCdcConfig {
    
    @Bean
    public OracleChangeStream oracleChangeStream() {
        return new OracleChangeStream.Builder()
            .url("jdbc:oracle:thin:@//host:port/service")
            .username("user")
            .password("pass")
            .tables("SCHEMA.TABLE")
            .build();
    }
    
    @Bean
    public MessageChannel changeStreamChannel() {
        return new DirectChannel();
    }
    
    @Bean
    @ServiceActivator(inputChannel = "changeStreamChannel")
    public MessageHandler changeStreamHandler() {
        return message -> {
            System.out.println("Received change: " + message.getPayload());
        };
    }
}

5. 使用Oracle LogMiner (11g及以上版本)

// 使用JDBC执行LogMiner操作
public class OracleLogMinerExample {
    public static void main(String[] args) throws SQLException {
        try (Connection conn = DriverManager.getConnection(url, username, password)) {
            Statement stmt = conn.createStatement();
            
            // 添加日志文件
            stmt.execute("BEGIN DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/path/to/log1.arc'); END;");
            stmt.execute("BEGIN DBMS_LOGMNR.ADD_LOGFILE(LOGFILENAME => '/path/to/log2.arc'); END;");
            
            // 开始LogMiner
            stmt.execute("BEGIN DBMS_LOGMNR.START_LOGMNR(OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG); END;");
            
            // 查询变更数据
            ResultSet rs = stmt.executeQuery("SELECT * FROM V$LOGMNR_CONTENTS");
            while (rs.next()) {
                System.out.println("Operation: " + rs.getString("OPERATION"));
                System.out.println("Table: " + rs.getString("TABLE_NAME"));
                System.out.println("SQL: " + rs.getString("SQL_REDO"));
            }
            
            // 结束LogMiner
            stmt.execute("BEGIN DBMS_LOGMNR.END_LOGMNR(); END;");
        }
    }
}

注意事项

  1. 权限要求:执行CDC或LogMiner操作需要特定的数据库权限
  2. 性能影响:持续监控对生产数据库的性能影响
  3. 连接稳定性:确保应用能处理网络中断和重连
  4. Oracle版本:不同版本支持的功能不同(如XStream需要12c+)
  5. 资源消耗:CDC和LogMiner可能会增加数据库负载

最佳实践建议

  1. 对于新项目,优先考虑Debezium等成熟框架
  2. 生产环境建议使用Kafka作为消息中间件缓冲变更事件
  3. 实现幂等处理,防止重复消费导致的数据问题
  4. 考虑使用分布式事务确保数据一致性
  5. 监控订阅延迟,确保及时处理变更

以上方法可以根据您的具体Oracle版本、性能需求和架构复杂度进行选择。

posted @ 2025-12-05 15:49  蓝迷梦  阅读(35)  评论(0)    收藏  举报