一、Flink Table\SQL API 简介
1.1 核心概述
Apache Flink 提供 Table API 和 SQL API 两套关系型 API,核心目标是统一流处理与批处理 ,是 Flink 高阶数据处理的核心能力。两套 API 底层基于 Apache Calcite 框架实现 SQL 解析、校验、优化,屏蔽了流批引擎差异。
-
Table API:基于 Java/Scala/Python 封装的流式查询 API,以 Lambda 表达式链式调用,语法贴近 SQL,兼顾代码灵活性与可读性。
-
SQL API:完全兼容标准 SQL 语法,降低大数据开发门槛,支持常规 DDL、DML、DQL 语句。
1.2 核心特性:流批统一
Flink Table&SQL 实现了用户接口层面的流批语义统一,是其最核心的优势:
-
同一条查询语句,无需修改代码,可同时适配有界批数据 (HDFS、Hive)和无界流数据(Kafka、Pulsar);
-
流、批模式下查询语义完全一致,计算结果逻辑统一;
-
底层引擎自动适配执行策略,批模式启用批量优化,流模式启用实时增量计算。
二、运行环境与依赖配置
本文所有内容基于 Flink 1.17.2 版本,该版本已废弃旧版 Flink Planner,仅支持 Blink Planner 作为唯一查询优化器。
2.1 核心依赖模块解析
2.1.1 flink-table-api-java-bridge / scala-bridge
核心前端 API 模块,是 Table&SQL 编程的基础依赖。
核心功能:
-
提供 Table 环境入口、基础运行时能力;
-
支持基础 SQL 解析与执行逻辑(不含优化器);
-
实现 Table API 与 DataStream API 的双向互操作。
注意事项:
-
必须配合 Planner 模块使用,本地开发依赖
flink-table-planner-blink,集群内置 Planner; -
生产环境需随作业 Jar 包提交;
-
纯 SQL 作业也必须依赖该模块提供运行时支撑。
2.1.2 flink-table-planner-blink
核心后端优化执行模块,SQL 引擎的核心。
核心功能:
-
基于 Apache Calcite 实现 SQL 语法校验、逻辑优化、物理优化;
-
生成最优查询执行计划,完成 SQL 到 Flink 算子的转换。
注意事项:
-
本地开发必须引入,生产集群已内置,依赖 scope 设为
provided; -
与 bridge 模块对应前后端关系,缺一不可。
2.1.3 flink-table-common(非必需)
Table 模块通用抽象层,面向扩展开发。
核心功能:定义 Table、Catalog、UDF 通用抽象接口,提供自定义 Connector、Format、UDF 的 SPI 扩展点。
注意事项:
-
普通业务开发无需主动依赖,仅自定义扩展场景需要;
-
生产环境需随 Jar 提交,版本必须与 Flink 核心版本严格一致。
2.2 Maven 依赖配置
2.2.1 Java 开发依赖
xml
<properties>
<flink.version>1.17.2</flink.version>
<scala.binary.version>2.12</scala.binary.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-api-java-bridge_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-planner-blink_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-common</artifactId>
<version>${flink.version}</version>
</dependency>
</dependencies>
2.2.2 Scala 开发依赖
xml
<properties>
<flink.version>1.17.2</flink.version>
<scala.binary.version>2.12</scala.binary.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-api-scala-bridge_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-planner-blink_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-common</artifactId>
<version>${flink.version}</version>
</dependency>
</dependencies>
三、核心代码结构与常用 API
3.1 标准代码执行流程
Flink Table&SQL 作业遵循固定开发模板,流程清晰统一:
-
通过
EnvironmentSettings配置执行模式(流/批); -
创建
TableEnvironment执行环境; -
定义数据源表、数据汇表;
-
通过 Table API/SQL API 编写计算逻辑;
-
执行写入,触发作业运行。
java
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.TableResult;
// 1. 配置执行环境(流模式/批模式)
EnvironmentSettings settings = EnvironmentSettings.newInstance()
.inStreamingMode() // 实时流任务
//.inBatchMode() // 离线批任务
.build();
// 2. 创建Table执行上下文
TableEnvironment tableEnv = TableEnvironment.create(settings);
// 3. 注册输入表
tableEnv.executeSql("CREATE TEMPORARY TABLE table1 ... WITH ( 'connector' = ... )");
// 4. 注册输出表
tableEnv.executeSql("CREATE TEMPORARY TABLE outputTable ... WITH ( 'connector' = ... )");
// 5. Table API 查询计算
Table table2 = tableEnv.from("table1").select(...);
// 6. SQL API 查询计算
Table table3 = tableEnv.sqlQuery("SELECT ... FROM table1 ... ");
// 7. 写入结果,执行作业
TableResult tableResult = table2.executeInsert("outputTable");
3.2 核心工具类详解
3.2.1 EnvironmentSettings
Table 环境配置类,用于定义作业核心运行模式:
-
指定执行模式:
inStreamingMode()流处理、inBatchMode()批处理; -
Flink 1.13+ 废弃 Planner 选择配置,默认唯一使用 Blink Planner;
-
支持绑定全局 Configuration 配置。
3.2.2 TableEnvironment / StreamTableEnvironment
Table&SQL 所有操作的入口上下文,管理作业全部运行时资源:
-
元数据管理:Catalog、数据库、表、视图;
-
函数管理:注册/删除临时 UDF、系统级 UDF;
-
SQL 执行:执行 DDL、DML、DQL 语句;
-
流批互通:支持 Table 与 DataStream 双向转换。
核心常用方法:
-
表管理:
createTemporaryView()、from()、dropTemporaryTable(); -
SQL 执行:
executeSql()(执行DDL/DML)、sqlQuery()(查询返回Table); -
UDF 管理:
createTemporaryFunction()、createTemporarySystemFunction()。
关键区别 :StreamTableEnvironment 绑定 DataStream 执行环境,共享 Checkpoint、水位线、时间语义,生产流作业优先使用。
3.2.3 Configuration
Flink 全局配置中心,线程安全,以键值对形式统一管理所有运行时参数,贯穿整个执行栈,支持并行度、Checkpoint、状态TTL、Table 优化参数等全局配置。
3.3 生产级环境模板
3.3.1 流式作业模板(生产首选)
适用于 Kafka、Pulsar 等实时数据源,默认开启容错、状态管理、Checkpoint 机制。
java
import org.apache.flink.configuration.Configuration;
import org.apache.flink.configuration.CoreOptions;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
import org.apache.flink.table.api.config.ExecutionConfigOptions;
import org.apache.flink.table.api.config.TableConfigOptions;
import java.time.Duration;
public class StreamingTableEnvTemplate {
public static void main(String[] args) {
// 1. 全局配置初始化
Configuration config = new Configuration();
config.set(CoreOptions.DEFAULT_PARALLELISM, 4);
config.set(CoreOptions.CHECK_LEAKED_CLASSLOADER, false);
// 2. Checkpoint 核心容错配置
config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_INTERVAL, Duration.ofSeconds(30));
config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_TIMEOUT, Duration.ofMinutes(10));
config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_MIN_PAUSE, Duration.ofSeconds(5));
config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_MAX_CONCURRENT, 1);
config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_EXTERNALIZED_CHECKPOINT,
ExecutionConfigOptions.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
// 3. 状态与执行优化配置
config.set(TableConfigOptions.TABLE_EXEC_RESOURCE_DEFAULT_PARALLELISM, 4);
config.set(TableConfigOptions.TABLE_EXEC_STATE_TTL, Duration.ofHours(24));
config.set(TableConfigOptions.TABLE_EXEC_SOURCE_IDLE_TIMEOUT, Duration.ofMinutes(5));
// 4. 创建流执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(config);
// 5. 创建Table环境,绑定流环境
EnvironmentSettings settings = EnvironmentSettings.newInstance()
.inStreamingMode()
.withConfiguration(config)
.build();
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings);
}
}
3.3.2 批量作业模板
适用于 Hive、HDFS、JDBC 离线数据源,无需 Checkpoint 和状态 TTL,自动启用批量执行优化。
java
import org.apache.flink.configuration.Configuration;
import org.apache.flink.configuration.CoreOptions;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
import org.apache.flink.table.api.config.TableConfigOptions;
public class BatchTableEnvTemplate {
public static void main(String[] args) {
Configuration config = new Configuration();
config.set(CoreOptions.DEFAULT_PARALLELISM, 8);
config.set(TableConfigOptions.TABLE_EXEC_RESOURCE_DEFAULT_PARALLELISM, 8);
config.set(TableConfigOptions.TABLE_EXEC_EMIT_EARLY_FIRE_ENABLED, false);
EnvironmentSettings settings = EnvironmentSettings.newInstance()
.inBatchMode()
.withConfiguration(config)
.build();
TableEnvironment tableEnv = TableEnvironment.create(settings);
}
}
四、动态表核心概念
4.1 动态表定义
动态表(Dynamic Table)是 Flink 对流式无限数据的逻辑表抽象,是 Table&SQL API 的核心底层概念:
-
本质是持续变化的逻辑表,无固定数据快照,数据随流实时更新;
-
任意时刻均可像静态批表一样执行查询;
-
所有 Flink SQL 查询都是基于动态表的持续增量计算。
4.2 三层命名空间规则
Flink 所有表、视图遵循 Catalog.数据库.表名 三层命名规范:[catalog_name.][database_name.]table_name
默认命名空间:
-
默认 Catalog:
default_catalog -
默认数据库:
default_database
4.3 动态表分类
4.3.1 按数据来源分类
-
物理表(Physical Table)
-
通过
CREATE TABLE语句创建,与外部存储系统(Kafka、MySQL、Hive)绑定; -
数据真实存储在外部系统,Flink 仅维护 Schema 元数据;
-
拥有固定字段结构,通过 Connector 完成序列化/反序列化。
-
-
逻辑视图(View)
-
通过
CREATE VIEW ... AS SELECT创建,仅存储查询逻辑,不存储任何数据; -
每次被引用都会重新执行底层查询;
-
用于简化复杂查询、逻辑分层,推荐使用临时视图。
-
4.3.2 按生命周期分类
-
临时表/视图(Temporary)
-
仅当前 Session 会话有效,作业重启后失效;
-
内存存储,优先级高于同名持久化表;
-
适合临时测试、作业内逻辑封装。
-
-
持久化表(Persistent)
-
元数据存储在 Catalog 中,跨会话、跨作业有效;
-
作业重启后可直接复用表定义,无需重复建表;
-
生产环境核心使用方式,依赖 HiveCatalog 等持久化元数据组件。
-
4.4 关键误区:Flink 物化视图
Flink 无传统数据库的物化视图 ,所有视图均为逻辑视图,不缓存计算结果。但 Flink 通过三大机制天然实现动态物化视图语义:
-
持续计算:基于流式数据实时增量更新计算结果;
-
状态管理:自动维护聚合、Join 等算子的计算状态;
-
外部持久化:通过 Sink 将结果写入外部存储,实现结果落地复用。
4.5 Table 与 DataStream 互转
生产环境较少使用,核心适用场景:SQL 负责批量计算,DataStream 负责自定义复杂逻辑(报警、特殊处理)。
java
// 场景:统计补贴券发放总金额,超1w触发报警
// 1. 定义数据源表
String createTableSql = "CREATE TABLE source_table (\n"
+ " id BIGINT,\n"
+ " money BIGINT,\n"
+ " row_time AS cast(CURRENT_TIMESTAMP as timestamp_LTZ(3)),\n"
+ " WATERMARK FOR row_time AS row_time - INTERVAL '5' SECOND\n"
+ ") WITH (\n"
+ " 'connector' = 'datagen',\n"
+ " 'rows-per-second' = '1'\n"
+ ")";
// 2. SQL 累计聚合计算
String querySql = "SELECT UNIX_TIMESTAMP(CAST(window_end AS STRING)) * 1000 as window_end, \n"
+ " window_start, \n"
+ " sum(money) as sum_money\n"
+ "FROM TABLE(CUMULATE(\n"
+ " TABLE source_table\n"
+ " , DESCRIPTOR(row_time)\n"
+ " , INTERVAL '5' SECOND\n"
+ " , INTERVAL '1' DAY))\n"
+ "GROUP BY window_start, window_end";
tableEnv.executeSql(createTableSql);
Table resultTable = tableEnv.sqlQuery(querySql);
// 3. Table 转 DataStream,自定义报警逻辑
tableEnv.toDataStream(resultTable, Row.class)
.flatMap((Row value, Collector<Object> out) -> {
long totalMoney = Long.parseLong(String.valueOf(value.getField("sum_money")));
if (totalMoney > 10000L) {
System.out.println("报警:补贴券发放总金额超过1w,当前金额:" + totalMoney);
}
});
五、Catalog 元数据管理
5.1 Catalog 核心作用
Catalog 是 FlinkSQL 的元数据管理中心,统一管理数据库、表、视图、函数、分区等所有元数据,核心价值:
-
解耦计算与元数据:表定义、Schema、连接器配置与代码分离,SQL 更简洁通用;
-
跨会话持久化:持久化 Catalog 可实现元数据跨作业、跨重启复用;
-
多租户隔离:多 Catalog、多数据库实现业务资源逻辑隔离;
-
外部元数据复用:直接对接 Hive、MySQL 元数据,无需重复建表。
5.2 Flink 内置 Catalog 类型
5.2.1 GenericInMemoryCatalog(默认)
-
基于内存实现,元数据仅当前 Session 有效,作业停止即丢失;
-
区分大小写,仅适用于本地测试、临时查询;
-
无需手动配置,系统默认启用。
5.2.2 JdbcCatalog
-
通过 JDBC 协议对接关系型数据库,目前仅支持 Postgres;
-
可直接映射数据库表为 Flink 表,复用存量元数据。
5.2.3 HiveCatalog(生产标配)
-
对接 Hive Metastore,实现元数据持久化存储;
-
支持读写 Hive 表、分区、函数,完美适配数仓体系;
-
元数据默认小写存储,生产环境必备。
java
// 代码注册HiveCatalog
String name = "myhive";
String defaultDatabase = "mydatabase";
String hiveConfDir = "/opt/hive-conf";
HiveCatalog hiveCatalog = new HiveCatalog(name, defaultDatabase, hiveConfDir);
tableEnv.registerCatalog("myhive", hiveCatalog);
tableEnv.useCatalog("myhive");
5.3 Catalog 常用 SQL 操作
sql
-- 1. 创建各类Catalog
CREATE CATALOG hive_catalog WITH (
'type' = 'hive',
'hive-conf-dir' = '/path/to/hive/conf',
'hadoop-conf-dir' = '/path/to/hadoop/conf',
'default-database' = 'default'
);
CREATE CATALOG jdbc_catalog WITH (
'type' = 'jdbc',
'default-database' = 'business_db',
'username' = 'flink_user',
'password' = 'flink_password',
'base-url' = 'jdbc:mysql://localhost:3306'
);
-- 2. 查看与切换Catalog
SHOW CATALOGS;
USE CATALOG hive_catalog;
SHOW CURRENT CATALOG;
-- 3. 跨Catalog操作表
CREATE TABLE hive_catalog.dim_db.user_dim (
user_id BIGINT,
user_name STRING
) WITH (...);
六、Flink SQL 完整数据类型体系
Flink Table&SQL 拥有独立的类型系统,兼容 SQL 标准,同时适配 JVM 语言类型,包含原子类型、复合类型、自定义类型三大类,支持空值判定、物理类型映射,适配序列化与存储场景。
6.1 原子数据类型
6.1.1 数值类型
| 类型 | 字节数 | 说明 | 对应Java类型 |
|---|---|---|---|
| TINYINT | 1 | 字节整数,范围 -128~127 | Byte |
| SMALLINT | 2 | 短整数,范围 -32768~32767 | Short |
| INT/INTEGER | 4 | 常用整数 | Integer |
| BIGINT | 8 | 长整数 | Long |
| FLOAT | 4 | 单精度浮点,有损精度 | Float |
| DOUBLE | 8 | 双精度浮点,有损精度 | Double |
| DECIMAL(p,s)/NUMERIC(p,s) | 可变 | 高精度无损小数,p总位数(1-38),s小数位数(0-p) | BigDecimal |
6.1.2 字符类型
| 类型 | 说明 | 备注 |
|---|---|---|
| CHAR(n) | 定长字符串,空格填充 | n默认1,最大2147483647 |
| VARCHAR(n) | 可变长度字符串 | n默认1 |
| STRING | 超长可变字符串 | 等价于 VARCHAR(2147483647) |
6.1.3 时间类型
| 类型 | 说明 | 精度规则 |
|---|---|---|
| DATE | 年月日日期,无时区 | 无精度 |
| TIME(p) | 时分秒时间,无时区 | p固定为0 |
| TIMESTAMP(p) | 时间戳,无时区 | p固定为3(毫秒),默认6 |
| TIMESTAMP_LTZ(p) | 带本地时区时间戳 | 时区由全局参数配置 |
| INTERVAL | 时间间隔类型 | 支持 YEAR TO MONTH、DAY TO SECOND |
6.1.4 其他基础类型
-
BOOLEAN:布尔类型,true/false
-
BINARY(n):定长二进制字节数组
-
VARBINARY(n)/BYTES:可变二进制数组,BYTES 等价于 VARBINARY(2147483647)
-
RAW:原始类型,保留对象原始结构,仅序列化传输,需指定Java类型与序列化器
-
NULL:空值类型
6.2 复合数据类型
复合类型序列化开销高于原子类型,性能关键路径需谨慎使用。
6.2.1 ARRAY 数组类型
存储同类型元素集合,最大长度 2147483647,索引从1开始。
sql
ARRAY<INT>
ARRAY<STRING>
-- 常用函数
SELECT tags[1], CARDINALITY(tags) FROM events;
6.2.2 MAP 映射类型
键值对集合,同组 key/value 类型统一。
sql
MAP<STRING, INT>
-- 常用操作
SELECT config['timeout'], MAP_KEYS(config) FROM settings;
6.2.3 MULTISET 多重集合
支持元素重复的集合类型,对应 Java List。
6.2.4 ROW 行类型
微型结构化表,包含多个命名字段,对应 Flink Row 对象,支持嵌套。
sql
ROW<name STRING, age INT, score DOUBLE>
-- 嵌套字段访问
SELECT address.city FROM users;
6.3 自定义数据类型
6.3.1 POJO 结构化自定义类型
Flink 可自动识别符合规范的 POJO,支持通过注解指定字段数据类型。
java
public class User {
public int age;
public String name;
// 注解指定高精度小数类型
public @DataTypeHint("DECIMAL(10, 2)") BigDecimal totalBalance;
}
// 自定义UDF使用POJO类型
public class UserScalarFunction extends ScalarFunction {
public User eval(long i) {
User user = new User();
user.age = (int) i;
user.name = "test";
user.totalBalance = new BigDecimal(1.1d);
return user;
}
}
6.3.2 UDT 完全自定义原生类型
通过继承 UserDefinedType 实现完全自定义类型,适配地理坐标、IP 等特殊业务类型,需手动实现序列化与注册逻辑。
七、总结
-
Flink Table&SQL 核心价值是流批统一,一套代码适配流、批双场景,大幅降低开发成本;
-
运行环境依赖分为前端 API 模块与后端优化器模块,生产环境需严格区分依赖 scope;
-
动态表是流式 SQL 的核心原理,通过持续增量计算+状态管理实现动态物化视图效果;
-
Catalog 实现元数据持久化与统一管理,HiveCatalog 是生产环境标配;
-
Flink 类型体系完善,原子类型高效稳定,复合类型灵活适配复杂场景,POJO 自定义类型适配个性化业务。