実際、JDBC コネクタは削除ステートメントも実行します。update_before および delete タイプのメッセージを受信した後、DDL で構成された主キーに従って削除ステートメントが生成および実行され、where 条件のフィールドが主キーになります。
まずは公式 Web サイトの内容を見てみましょう。
主キーが DDL で定義されている場合、JDBC レシーバーは通常の INSERT ステートメントの代わりに upsert セマンティクスを使用します。Upsert セマンティクスとは、基になるデータベースに一意制約違反がある場合に、新しい行を自動的に追加するか、既存の行を更新することを指し、冪等性が提供されます。
upsert には標準の構文がないため、次の表に、使用されるデータベース固有の DML を示します。
これはデータの挿入のみを目的としており、実際には、JDBC コネクタは削除ステートメントも実行します。update_before および delete タイプのメッセージを受信した後、DDL で構成された主キーに従って削除ステートメントが生成および実行され、where 条件のフィールドが主キーになります。
以下は、TableBufferReducedStatementExecutor クラスのコア ロジックです。
@Override
public void addToBatch(RowData record) throws SQLException {
RowData key = keyExtractor.apply(record);
boolean flag = changeFlag(record.getRowKind());
RowData value = valueTransform.apply(record); // copy or not
reduceBuffer.put(key, Tuple2.of(flag, value));
}
/**
* Returns true if the row kind is INSERT or UPDATE_AFTER, returns false if the row kind is
* DELETE or UPDATE_BEFORE.
*/
private boolean changeFlag(RowKind rowKind) {
switch (rowKind) {
case INSERT:
case UPDATE_AFTER:
return true;
case DELETE:
case UPDATE_BEFORE:
return false;
default:
throw new UnsupportedOperationException(
String.format(
"Unknown row kind, the supported row kinds is: INSERT, UPDATE_BEFORE, UPDATE_AFTER,"
+ " DELETE, but get: %s.",
rowKind));
}
}
@Override
public void executeBatch() throws SQLException {
for (Map.Entry<RowData, Tuple2<Boolean, RowData>> entry : reduceBuffer.entrySet()) {
if (entry.getValue().f0) {
upsertExecutor.addToBatch(entry.getValue().f1);
} else {
// delete by key
deleteExecutor.addToBatch(entry.getKey());
}
}
upsertExecutor.executeBatch();
deleteExecutor.executeBatch();
reduceBuffer.clear();
}