利用flink的DatStream API 创建任务
public static void main(String[] args) throws Exception {
SourceFunction<String> sourceFunction = OracleSource.<String>builder()
.url("jdbc:oracle:thin:@hadoop103:1521:ORCL") // 用来连接oracle的url
.port(1521) // oracle 的端口号
.database("ORCL") // 监听的数据库
.schemaList("SCOTT") // 监听的schema
.tableList("SCOTT.USERS ,SCOTT.APPS") // 监听的表
.username("system") // 用户名
.password("Oracle123") // 密码
// .deserializer(new JsonDebeziumDeserializationSchema()) // 将结果以json格式进行输出。
.deserializer(new OracleDeserializationSchema ()) // 自定义的输出格式
.build();
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.addSource(sourceFunction)
.print().setParallelism(1); // use parallelism 1 for sink to keep message ordering
env.execute();
}
自定义输出格式 - -> {schema:xx , table:xx, data:{xx:xx,yy:yy}}
import com.alibaba.fastjson.JSONObject;
import com.ververica.cdc.debezium.DebeziumDeserializationSchema;
import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.util.Collector;
import org.apache.kafka.connect.data.Field;
import org.apache.kafka.connect.data.Schema;
import org.apache.kafka.connect.data.Struct;
import org.apache.kafka.connect.source.SourceRecord;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
public class OracleDeserializationSchema implements DebeziumDeserializationSchema<String> {
@Override
public void deserialize(SourceRecord record, Collector<String> out) throws Exception {
JSONObject result = new JSONObject(new LinkedHashMap<>());
/*得到schema 和 table*/
String topic = record.topic();
String[] fields = topic.split("\\.");
result.put("schema", fields[1]);
result.put("table", fields[2]);
/*得到after数据*/
Struct value = (Struct) record.value();
Struct after = (Struct) value.get("after");
JSONObject afterJson = new JSONObject(new LinkedHashMap<>());
if (after != null) {
Schema schema = after.schema();
List<Field> fieldList = schema.fields();
for (Field field : fieldList) {
/*
由于通过归档日志读取到的number类型的数据格式为:{scale=2,value=[B@6e0782b5}
scale :数值的精度,及小数点后几位;value:数值的二进制数组的格式
需要将改格式转化成实际数据库中存储的格式
主要思路是,将value的值转化为 long类型,将scale的值转化为int类型,通过BigDecimal.valueOf()方法得到存储的值
*/
if (after.get(field) instanceof Struct) {
Struct fieldValue = (Struct) after.get(field);
byte[] bytes = fieldValue.getBytes("value");
String l = Byte.toString(bytes[0]);
afterJson.put(field.name(), l);
Integer scale = fieldValue.getInt32("scale");
BigDecimal valueOf = BigDecimal.valueOf(Long.valueOf(l), scale);
afterJson.put(field.name(), valueOf.toString());
} else {
afterJson.put(field.name(), after.get(field));
}
}
}
result.put("data", afterJson);
out.collect(result.toJSONString());
}
@Override
public TypeInformation<String> getProducedType() {
return BasicTypeInfo.STRING_TYPE_INFO;
}
}
问题及解决
1、归档日志满了怎么办 ,也就是报错:ORA-00257: archiver error. Connect internal only, until freed
rman target sys/pass
crosscheck archivelog all;
delete expired archivelog all;
2、Oracle CDC 的归档日志增长很快,且读取 log 慢?
可以使用在线挖掘的模式,不写入数据字典到 redo log 中,但是这样无法处理 DDL 语句。 生产环境默认策略读取 log 较慢,且默认策略会写入数据字典信息到 redo log 中导致日志量增加较多,可以添加如下 debezium 的配置项。 'log.mining.strategy' = 'online_catalog'
, 'log.mining.continuous.mine' = 'true'
。如果使用 SQL 的方式,则需要在配置项中加上前缀 'debezium.'
,即:
请不要在连接到 Oracle 12c 或更高版本时使用该参数
Properties debeziumProperties = new Properties();
debeziumProperties.setProperty("log.mining.strategy", "online_catalog");
debeziumProperties.setProperty("log.mining.continuous.mine", "true");
builder.debeziumProperties(debeziumProperties);
3、作业报错 Caused by: io.debezium.DebeziumException: Supplemental logging not configured for table xxx. Use command: ALTER TABLE xxx ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS, 怎么办呢?
对于 oracle11 版本,debezium 会默认把 tableIdCaseInsensitive 设置为true, 导致表名被更新为小写,因此在oracle中查询不到 这个表补全日志设置,导致误报这个Supplemental logging not configured for table 错误”。 添加 debezium 的配置项 'database.tablename.case.insensitive' = 'false'
, 如果使用 SQL 的方式,则在表的 option 中添加配置项 'debezium.database.tablename.case.insensitive' = 'false'
4、 Oracle CDC 如何切换成 XStream 的方式?
添加 debezium 的配置项 'database.connection.adpter' = 'xstream'
, 如果使用 SQL 的方式,则在表的 option 中添加配置项 'debezium.database.connection.adpter' = 'xstream'
5、 Oracle CDC 的 database-name 和 schema-name 分别是什么
database-name 是数据库示例的名字,也就是 Oracle 的 SID schema-name 是表对应的 schema,一般而言,一个用户就对应一个 schema, 该用户的 schema 名等于用户名,并作为该用户缺省 schema。所以 schema-name 一般都是创建这个表的用户名,但是如果创建表的时候指定了 schema,则指定的 schema 则为 schema-name。 比如用 CREATE TABLE aaaa.testtable(xxxx) 的方式成功创建了表 testtable, 则 aaaa 为 schema-name。
参考:
Oracle CDC Connector — CDC Connectors for Apache Flink® documentation (ververica.github.io)
FAQ(ZH) · ververica/flink-cdc-connectors Wiki · GitHub
6、Oracle CDC 读取不到大文件,即:BLOB 和 CLOB 类型的数据
这是由于 debezium 的参数 lob.enabled
决定的,默认为 false
,可以修改为 lob.enabled=true
该参数的作用是:控制是否在更改事件中发出大型对象(CLOB 或 BLOB)列值。
默认情况下,变更事件具有较大的对象列,但这些列不包含任何值。 在处理和管理大型对象列类型和有效负载时存在一定的开销。 要捕获大型对象值并在更改事件中序列化这些值,请将此选项设置为 。true