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;");
}
}
}
注意事项
- 权限要求:执行CDC或LogMiner操作需要特定的数据库权限
- 性能影响:持续监控对生产数据库的性能影响
- 连接稳定性:确保应用能处理网络中断和重连
- Oracle版本:不同版本支持的功能不同(如XStream需要12c+)
- 资源消耗:CDC和LogMiner可能会增加数据库负载
最佳实践建议
- 对于新项目,优先考虑Debezium等成熟框架
- 生产环境建议使用Kafka作为消息中间件缓冲变更事件
- 实现幂等处理,防止重复消费导致的数据问题
- 考虑使用分布式事务确保数据一致性
- 监控订阅延迟,确保及时处理变更
以上方法可以根据您的具体Oracle版本、性能需求和架构复杂度进行选择。
本文来自博客园,作者:蓝迷梦,转载请注明原文链接:https://www.cnblogs.com/hewei-blogs/articles/19312501

浙公网安备 33010602011771号