【flink-sql实战】flink 主键声明与upsert功能实战

本文介绍了Flink中主键的声明语法,包括单列和联合主键,以及如何在物理表创建时使用它们进行数据优化。重点讲解了主键的非空约束和唯一性检查,以及在FlinkSQL中与MySQL等RDBMS的集成操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. flink 主键声明语法

主键用作 Flink 优化的一种提示信息。主键限制表明一张表或视图的某个(些)列是唯一的并且不包含 Null 值。 主键声明的列都是非 nullable 的。因此主键可以被用作表行级别的唯一标识。

主键可以和列的定义一起声明,也可以独立声明为表的限制属性,不管是哪种方式,主键都不可以重复定义,否则 Flink 会报错。

 
有效性检查

SQL 标准主键限制可以有两种模式:ENFORCED 或者 NOT ENFORCED。 它申明了是否输入/出数据会做合法性检查(是否唯一)。
 
Flink 不存储数据因此只支持 NOT ENFORCED 模式,即不做检查,用户需要自己保证唯一性。

注意: 在 CREATE TABLE 语句中,创建主键会修改列的 nullable 属性,主键声明的列默认都是非 Nullable 的。

 
sql声明语法:

CREATE TABLE [IF NOT EXISTS] [catalog_name.][db_name.]table_name
  (
    { <physical_column_definition> | <metadata_column_definition> | <computed_column_definition> }[ , ...n]
    [ <watermark_definition> ]
    [ <table_constraint> ][ , ...n]
  )
 ...

<column_constraint>:
  [CONSTRAINT constraint_name] PRIMARY KEY NOT ENFORCED

<table_constraint>:
  [CONSTRAINT constraint_name] PRIMARY KEY (column_name, ...) NOT ENFORCED
...

联合主键声明

 create table t_sink_01 ( 
f1 varchar, 
f2 varchar,
f3 int,
f4 timestamp(3),
f5 varchar, 
primary key(f1,f2)  NOT ENFORCED  -- 主键声明,字段之间逗号分隔
)
with( 
..
) ;

 
 

二. 物理表创建联合主键表

CREATE TABLE test003(
     id INT(10),
     name VARCHAR(25),
     age int(10),
     PRIMARY KEY(id,name));


desc test003

Field|Type       |Null|Key|Default|Extra|
-----+-----------+----+---+-------+-----+
id   |int        |NO  |PRI|       |     |
name |varchar(25)|NO  |PRI|       |     |
age  |int        |YES |   |       |     |

 

三. flink sql使用

CREATE TABLE source
(   `id` int,
 	`username` varchar,
 	`age` int
) WITH (
  'connector' = 'binlog-x'
      ,'username' = 'root'
      ,'password' = '11111111'
      ,'cat' = 'insert,delete,update'
      ,'url' = 'jdbc:mysql://10.17.31.234:3306/360test'
      ,'host' = '10.17.31.234'
      ,'port' = '3306'
      -- 什么都不加:最新位置消费
      -- 加文件名,从此文件开头消费
       ,'journal-name' = 'binlog.000194'
      --  ,'timestamp'='169944781200'
      ,'table' = '360test.dimension_table'
      ,'timestamp-format.standard' = 'SQL'
      );
CREATE TABLE sink
(   `id` int,
 	`name` varchar,
 	`age` int,
 	PRIMARY KEY (id,name) NOT ENFORCED
) WITH (
        'connector' = 'mysql-x',
           'url' = 'jdbc:mysql://localhost:3306/360test',
           'table-name' = 'test003',
           'username' = 'root',
           'password' = '11111111',
           'sink.buffer-flush.max-rows' = '1024', -- 批量写数据条数,默认:1024
           'sink.buffer-flush.interval' = '10000', -- 批量写时间间隔,默认:10000毫秒
           -- insert时的选项,覆盖或者忽略。
           -- 声明了主键时,设置all-replace为true,全部更新覆盖,
           -- 或者是忽略,即来的新数据不插入?
           'sink.all-replace' = 'true', -- 解释如下(其他rdb数据库类似):默认:false。定义了PRIMARY KEY才有效,否则是追加语句
                                       -- sink.all-replace = 'true' 生成如:INSERT INTO `result3`(`mid`, `mbb`, `sid`, `sbb`) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE `mid`=VALUES(`mid`), `mbb`=VALUES(`mbb`), `sid`=VALUES(`sid`), `sbb`=VALUES(`sbb`) 。会将所有的数据都替换。
                                       -- sink.all-replace = 'false' 生成如:INSERT INTO `result3`(`mid`, `mbb`, `sid`, `sbb`) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE `mid`=IFNULL(VALUES(`mid`),`mid`), `mbb`=IFNULL(VALUES(`mbb`),`mbb`), `sid`=IFNULL(VALUES(`sid`),`sid`), `sbb`=IFNULL(VALUES(`sbb`),`sbb`) 。如果新值为null,数据库中的旧值不为null,则不会覆盖。
           -- 新增写入选项:默认会判断,当声明了key则是update
           'sink.parallelism' = '1'    -- 写入结果的并行度,默认:null
      );
insert into sink select id,username as name,age as age  from source;


### 使用 Flink SQLUpsert-Kafka 连接器 Upsert-Kafka 是 Apache Flink 提供的一种用于 Kafka 交互的方式,允许通过 UPSERT 模式写入和读取数据。这种方式特别适用于需要更新记录的应用场景。 #### 创建表定义 为了使用 Upsert-Kafka 连接器,在创建表时需指定 `connector` 类型为 `'upsert-kafka'` 并提供必要的配置选项: ```sql CREATE TABLE kafka_table ( user_id BIGINT, name STRING, balance DECIMAL(10, 2), PRIMARY KEY (user_id) NOT ENFORCED ) WITH ( 'connector' = 'upsert-kafka', 'topic' = 'balance_updates', -- Kafka topic 名称 'properties.bootstrap.servers' = 'localhost:9092', -- Kafka broker 地址 'key.format' = 'json', -- 键格式 'value.format' = 'json' -- 值格式 ); ``` 此命令定义了一个名为 `kafka_table` 的表,其结构映射到 Kafka 主题中的消息[^1]。 #### 插入新记录或更新现有记录 一旦设置了上述表,可以执行标准的 INSERT INTO 语句来向 Kafka 发送新的键值对或者覆盖已存在的键对应的旧值: ```sql INSERT INTO kafka_table VALUES (1L, 'Alice', 120.50), (2L, 'Bob', 87.45); ``` 对于已经存在于目标主题内的任何具有相同主键 (`user_id`) 的条目来说,这将触发一次更新操作而不是插入一条全新的记录。 #### 查询来自 Kafka 的变更日志 除了能够发送更改外,还可以利用相同的机制从支持 upsert 功能的主题中消费事件流并将其作为动态视图呈现给查询引擎: ```sql SELECT * FROM kafka_table; ``` 这条 SELECT 语句将持续监听指定主题上的所有新增加/修改过的记录,并实时反映在结果集中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roman_日积跬步-终至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值