Flink 1.11 SQL 使用攻略

2023-05-16

7 月 6 日,Apache Flink 1.11 正式发布。从 3 月初进行功能规划到 7 月初正式发版,1.11 用将近 4 个月的时间重点优化了 Flink 的易用性问题,提升用户的生产使用体验。

 

SQL 作为 Flink 中公认的核心模块之一,对推动 Flink 流批一体功能的完善至关重要。在 1.11 中,Flink SQL 也进行了大量的增强与完善,开发大功能 10 余项,不仅扩大了应用场景,还简化了流程,上手操作更简单。

 

其中,值得注意的改动包括:

 

  • 默认 Planner 已经切到 Blink planner 上。

  • 引入了对 CDC(Change Data Capture,变动数据捕获)的支持,用户仅用几句简单的 SQL 即可对接 Debezium 和 Canal 的数据源。

  • 离线数仓实时化,用户可方便地使用 SQL 将流式数据从 Kafka 写入 Hive 等。

 

Flink SQL 演变

 

随着流计算的发展,挑战不再仅限于数据量和计算量,业务变得越来越复杂,开发者可能是资深的大数据从业者、初学 Java 的爱好者,或是不懂代码的数据分析者。如何提高开发者的效率,降低流计算的门槛,对推广实时计算非常重要。

 

SQL 是数据处理中使用最广泛的语言,它允许用户简明扼要地展示其业务逻辑。Flink 作为流批一体的计算引擎,致力于提供一套 SQL 支持全部应用场景,Flink SQL 的实现也完全遵循 ANSI SQL 标准。之前,用户可能需要编写上百行业务代码,使用 SQL 后,可能只需要几行 SQL 就可以轻松搞定。

 

Flink SQL 的发展大概经历了以下阶段:

 

  • Flink 1.1.0:第一次引入 SQL 模块,并且提供 TableAPI,当然,这时候的功能还非常有限。

  • Flink 1.3.0:在 Streaming SQL 上支持了 Retractions,显著提高了 Streaming SQL 的易用性,使得 Flink SQL 支持了复杂的 Unbounded 聚合连接。

  • Flink 1.5.0:SQL Client 的引入,标志着 Flink SQL 开始提供纯 SQL 文本。

  • Flink 1.9.0:抽象了 Table 的 Planner 接口,引入了单独的 Blink Table 模块。Blink Table 模块是阿里巴巴内部的 SQL 层版本,不仅在结构上有重大变更,在功能特性上也更加强大和完善。

  • Flink 1.10.0:作为第一个 Blink 基本完成 merge 的版本,修复了大量遗留的问题,并给 DDL 带来了 Watermark 的语法,也给 Batch SQL 带来了完整的 TPC-DS 支持和高效的性能。

 

经过了多个版本的迭代支持,SQL 模块在 Flink 中变得越来越重要,Flink 的 SQL 用户也逐渐扩大。基于 SQL 模块的 Python 接口和机器学习接口也在快速发展。毫无疑问, SQL 模块作为最常用的 API 之一和生态的集成变得越来越重要。

 

SQL 1.11 重要变更

 

Flink SQL 在原有的基础上扩展了新场景的支持:

 

  • Flink SQL 引入了对 CDC(Change Data Capture,变动数据捕获)的支持,它使 Flink 可以方便地通过像 Debezium 这类工具来翻译和消费数据库的变动日志。

  • Flink SQL 扩展了类 Filesystem connector 对实时化用户场景和格式的支持,从而可以支持将流式数据从 Kafka 写入 Hive 等场景。

 

除此之外,Flink SQL 也从多个方面提高 SQL 的易用性,系统性的解决了之前的 Bug、完善了用户 API。

 

CDC 支持

 

CDC 格式是数据库中一种常用的模式,业务上典型的应用是通过工具(比如 Debezium 或 Canal)将 CDC 数据通过特定的格式从数据库中导出到 Kafka 中。在以前,业务上需要定义特殊的逻辑来解析 CDC 数据,并把它转换成一般的 Insert-only 数据,后续的处理逻辑需要考虑到这种特殊性,这种 work-around 的方式无疑给业务上带来了不必要的复杂性。

 

如果 Flink SQL 引擎能原生支持 CDC 数据的输入,将 CDC 对接到 Flink SQL 的 Changelog Stream 概念上,将会大大降低用户业务的复杂度。

 

 

流计算的本质是就是不断更新、不断改变结果的计算。考虑一个简单的聚合 SQL,流计算中,每次计算产生的聚合值其实都是一个局部值,所以会产生 Changelog Stream。在以前想要把聚合的数据输出到 Kafka 中,如上图所示,几乎是不可能的,因为 Kafka 只能接收 Insert-only 的数据。

 

Flink 之前主要是因为 Source&Sink 接口的限制,导致不能支持 CDC 数据的输入。Flink SQL 1.11 经过了大量的接口重构,在新的 Source&Sink 接口上,支持了 CDC 数据的输入和输出,并且支持了 Debezium 与 Canal 格式(FLIP-105)。这一改动使动态 Table Source 不再只支持 append-only 的操作,而且可以导入外部的修改日志(插入事件)将它们翻译为对应的修改操作(插入、修改和删除)并将这些操作与操作的类型发送到后续的流中。

 

 

如上图所示,理论上,CDC 同步到 Kafka 的数据就是 Append 的一个流,只是在格式中含有 Changelog 的标识:

 

  • 一种方式是把 Changlog 标识看做一个普通字段,这也是目前普遍的使用方式。

  • 在 Flink 1.11 后,可以将它声明成 Changelog 的格式,Flink 内部机制支持 Interpret Changelog,可以原生识别出这个特殊的流,将其转换为 Flink 的 Changlog Stream,并按照 SQL 的语义处理;同理,Flink SQL 也具有输出 Change Stream 的能力 (Flink 1.11 暂无内置实现),这就意味着,你可以将任意类型的 SQL 写入到 Kafka 中,只要有 Changelog 支持的 Format。

 

为了消费 CDC 数据,用户需要在使用 SQL DDL 创建表时指指定“format=debezium-json”或者“format=canal-json”:

 

  •  
  •  
  •  
  •  
  •  
  •  
CREATE TABLE my_table (    ...) WITH (    'connector'='...', -- e.g. 'kafka'    'format'='debezium-json');

 

Flink 1.11 的接口都已 Ready,但是在实现上:

 

  • 只支持 Kafka 的 Debezium-json 和 Canal-json 读。

  • 欢迎大家扩展实现自己的 Format 和 Connector。

 

Source & Sink 重构

 

Source & Sink 重构的一个重要目的是支持上节所说的 Changelog,但是除了 Changelog 以外,它也解决了诸多之前的遗留问题。

 

新 Source & Sink 使用标准姿势 (详见官方文档):

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
CREATE TABLE kafka_table (    ...) WITH (    'connector' = 'kafka-0.10',    'topic' = 'test-topic',    'scan.startup.mode' = 'earliest-offset',    'properties.bootstrap.servers' = 'localhost:9092',    'format' = 'json',    'json.fail-on-missing-field' = 'false');

 

Flink 1.11 为了向前兼容性,依然保留了老 Source & Sink,使用 “connector.type” 的 Key,即可 Fallback 到老 Source & Sink 上。

 

■ Factory 发现机制

 

Flink 1.11 前,用户可能经常遇到一个异常,叫做 NoMatchingFactory 异常:

 

 

指的是,定义了一个 DDL,在用的时候,DDL 属性找不到对应的 TableFactory 实现,可能的原因是:

 

  • Classpath 下没有实现类,Flink SQL 是通过  Java SPI 的机制来发现 Factory;

  • 参数写错了。

 

但是报的异常让人非常疑惑,根据异常的提示消息,很难找到到底哪里的代码错了,更难明确知道哪个 Key 写错了。

 

  •  
  •  
  •  
  •  
public interface Factory {    String factoryIdentifier();    ……}

 

所以在 Flink 1.11 中,社区重构了 TableFactory 接口,提出了一个新的 Factory 接口,它有一个方法,叫做 FactoryIdentifier。以后所有的 Factory 的 look up 都通过 identifier。这样的话就非常清晰明了,找不到是因为 Classpath 下没 Factory 的类,找得到那就可以定位到 Factory 的实现中,进行确定性的校验。

 

■ 类型与数据结构

 

之前的 Source&Sink 接口支持用户自定义数据结构,即框架知道如何把自定义的数据结构转换为 Flink SQL 认识的内部数据结构,如:

 

  •  
  •  
  •  
  •  
public interface TableSource<T> {    TypeInformation<T> getReturnType();    ...}

 

用户可以自定义泛型 T,通过 getReturnType 来告诉框架怎么转换。

 

不过问题来了,当 getReturnType 和 DDL 中声明的类型不一致时怎么办?特别是两套类型系统的情况下,如:Runtime 的 TypeInformation,SQL 层的 DataType。由于精度等问题,可能导致经常出现类型不匹配的异常。

 

Flink 1.11 系统性地解决了这个问题。现在 Connector 开发者不能自定义数据结构,只能使用 Flink SQL 内部的数据结构:RowData。所以保证了默认 Type 与 DDL 的对应,不用再返回类型让框架去确认了。

 

RowData 数据结构在 SQL 内部设计出来为了:

 

  • 抽象类接口,在不同场景有适合的高性能实现。

  • 包含 RowKind,契合流计算中的 CDC 数据格式。

  • 遵循 SQL 规范,比如包含精度信息。

  • 对应 SQL 类型的可枚举的数据结构。

 

 

■ Upsert 与 Primary Key

 

流计算的一个典型场景是把聚合的数据写入到 Upsert Sink 中,比如 JDBC、HBase,当遇到复杂的 SQL 时,时常会出现:

 

 

UpsertStreamTableSink 需要上游的 Query 有完整的 Primary Key 信息,不然就直接抛异常。这个现象涉及到 Flink 的 UpsertStreamTableSink 机制。顾名思义,它是一个更新的 Sink,需要按 Key 来更新,所以必须要有 Key 信息。

 

如何发现 Primary Key?一个方法是让优化器从 Query 中推断,如下图发现 Primary Key 的例子。

 

这种情况下在简单 Query 当中很好,也满足语义,也非常自然。但是如果是一个复杂的 Query,比如聚合又 Join 再聚合,那就只有报错了。不能期待优化器有多智能,很多情况它都不能推断出 PK,而且,可能业务的 SQL 本身就不能推断出 PK,所以导致了这样的异常。

 

 

怎么解决问题?Flink 1.11 彻底的抛弃了这个机制,不再从 Query 来推断 PK 了,而是完全依赖 Create table 语法。比如 Create 一个 jdbc_table,需要在定义中显式地写好 Primary Key(后面 NOT ENFORCED 的意思是不强校验,因为 Connector 也许没有具备 PK 的强校验的能力)。当指定了 PK,就相当于就告诉框架这个Jdbc Sink 会按照对应的 Key 来进行更新。如此,就跟 Query 完全没有关系了,这样的设计可以定义得非常清晰,如何更新完全按照设置的定义来。

 

  •  
  •  
  •  
  •  
  •  
CREATE TABLE jdbc_table (    id BIGINT,    ...    PRIMARY KEY (id) NOT ENFORCED)

 

Hive 流批一体

 

首先看传统的 Hive 数仓。一个典型的 Hive 数仓如下图所示。一般来说,ETL 使用调度工具来调度作业,比如作业每天调度一次或者每小时调度一次。这里的调度,其实也是一个叠加的延迟。调度产生 Table1,再产生 Table2,再调度产生 Table3,计算延时需要叠加起来。

 

 

问题是慢,延迟大,并且 Ad-hoc 分析延迟也比较大,因为前面的数据入库,或者前面的调度的 ETL 会有很大的延迟。Ad-hoc 分析再快返回,看到的也是历史数据。

 

所以现在流行构建实时数仓,从 Kafka 读计算写入 Kafka,最后再输出到 BI DB,BI DB 提供实时的数据服务,可以实时查询。Kafka 的 ETL 为实时作业,它的延时甚至可能达到毫秒级。实时数仓依赖 Queue,它的所有数据存储都是基于 Queue 或者实时数据库,这样实时性很好,延时低。但是:

 

  • 第一,基于 Queue,一般来说就是行存加 Queue,存储效率其实不高。

  • 第二,基于预计算,最终会落到 BI DB,已经是聚合好的数据了,没有历史数据。而且 Kafka 存的一般来说都是 15 天以内的数据,没有历史数据,意味着无法进行 Ad-hoc 分析。所有的分析全是预定义好的,必须要起对应的实时作业,且写到 DB 中,这样才可用。对比来说,Hive 数仓的好处在于它可以进行 Ad-hoc 分析,想要什么结果,就可以随时得到什么结果。

 

 

能否结合离线数仓和实时数仓两者的优势,然后构建一个 Lambda 的架构?

 

核心问题在于成本过高。无论是维护成本、计算成本还是存储成本等都很高。并且两边的数据还要保持一致性,离线数仓写完 Hive 数仓、SQL,然后实时数仓也要写完相应 SQL,将造成大量的重复开发。还可能存在团队上分为离线团队和实时团队,两个团队之间的沟通、迁移、对数据等将带来大量人力成本。如今,实时分析会越来越多,不断的发生迁移,导致重复开发的成本也越来越高。少部分重要的作业尚可接受,如果是大量的作业,维护成本其实是非常大的。

 

如何既享受 Ad-hoc 的好处,又能实现实时化的优势?一种思路是将 Hive 的离线数仓进行实时化,就算不能毫秒级的实时,准实时也好。所以,Flink 1.11 在 Hive 流批一体上做了一些探索和尝试,如下图所示。它能实时地按 Streaming 的方式来导出数据,写到 BI DB 中,并且这套系统也可以用分析计算框架来进行 Ad-hoc 的分析。这个图当中,最重要的就是 Flink Streaming 的导入。

 

 

■ Streaming Sink

 

早期 Flink 版本在 DataStreaming 层,已经有一个强大的 StreamingFileSink 将流数据写到文件系统。它是一个准实时的、Exactly-once 的系统,能实现一条数据不多,一条数据不少的 Sink。

 

 

具体原理是基于两阶段提交:

 

  • 第一阶段:SnapshotPerTask,关闭需要 Commit 的文件,或者记录正在写的文件的 Offset。

  • 第二阶段:NotifyCheckpointComplete,Rename 需要 Commit 的文件。注意,Rename 是一个原子且幂等的操作,所以只要保证 Rename 的 At-least-once,即可保证数据的 Exactly-once。

 

这样一个 File system 的 Writer 看似比较完美了。但是在 Hive 数仓中,数据的可见性是依赖 Hive Metastore 的,那在这个流程中,谁来通知 Hive Metastore 呢?

 

 

SQL 层在 StreamingFileSink,扩展了 Partition 的 Committer。

 

相当于不仅要进行 File 的 Commit,还要进行 Partition 的 Commit。如图所示,FileWriter 对应之前的 StreamingFileSink,它提供的是 Exactly-once 的 FileWriter。而后面再接了一个节点 PartitionCommitter。支持的 Commit Policy 有:

 

  • 内置支持 Add partition 到 Hive metastore;

  • 支持写 SuccessFile 到文件系统当中;

  • 并且也可以自定义 Committer,比如可以 analysis partition、合并 partition 里面的小文件。

 

Committer 挂在 Writer 后, 由 Commit Trigger 决定什么时机来 commit :

 

  • 默认的 commit 时机是,有文件就立即 commit。因为所有 commit 都是可重入的,所以这一点是可允许的。

  • 另外,也支持通过 partition 时间和 Watermark 来共同决定的。比如小时分区,如果现在时间到 11 点,10 点的分区就可以 commit 了。Watermark 保证了作业当前的准确性。

 

■ Streaming Source

 

Hive 数仓中存在大量的 ETL 任务,这些任务往往是通过调度工具来周期性的运行,这样做主要有两个问题:

 

  • 实时性不强,往往调度最小也是小时级。

  • 流程复杂,组件多,容易出现问题。

 

针对这些离线的 ETL 作业,Flink 1.11 为此开发了实时化的 Hive 流读,支持:

 

  • Partition 表,监控 Partition 的生成,增量读取新的 Partition。

  • 非 Partition 表,监控文件夹内新文件的生成,增量读取新的文件。

 

甚至可以使用 10 分钟级别的分区策略,使用 Flink 的 Hive streaming source 和 Hive streaming sink ,可以大大提高 Hive 数仓的实时性到准实时分钟级,在实时化的同时,也支持针对 Table 全量的 Ad-hoc 查询,提高灵活性。

 

  •  
SELECT * FROM hive_table /*+ OPTIONS('streaming-source.enable'=’true’, 'streaming-source.consume-start-offset'='2020-05-20') */;

 

另外除了 Scan 的读取方式,Flink 1.11 也支持了 Temporal Join 的方式,也就是以前常说的 Streaming Dim Join。

 

  •  
  •  
  •  
  •  
  •  
  •  
SELECT  o.amout, o.currency, r.rate, o.amount * r.rateFROM  Orders AS o  JOIN LatestRates FOR SYSTEM_TIME AS OF o.proctime AS r  ON r.currency = o.currency

 

目前支持的方式是 Cache All,并且是不感知分区的,比较适合小表的情况。

 

■ Hive Dialect

 

Flink SQL 遵循的是 ANSI-SQL 的标准,而 Hive SQL 有它自己的 HQL 语法,它们之间的语法、语义都有些许不同。

 

如何让 Hive 用户迁移到 Flink 生态中,同时避免用户太大的学习成本?为此, Flink SQL 1.11 提供了 Hive Dialect,可以使得用户在 Flink 生态中使用 HQL 语言来计算。目前只支持 DDL,后续版本会逐步攻坚 Qeuries。

 

■ Filesystem Connector

 

Hive Integration 提供了一个重量级的集成,功能丰富,但是环境比较复杂。如果只是想要一个轻量级的 Filesystem 读写呢?

 

Flink table 在长久以来只支持一个 CSV 的 Filesystem Table,并且还不支持 Partition,行为上在某些方面也有些不符合大数据计算的直觉。

 

Flink 1.11 重构了整个 Filesystem connector 的实现:

 

  • 结合 Partition,现在,Filesystem connector 支持 SQL 中 Partition 的所有语义,支持 Partition 的 DDL,支持 Partition Pruning,支持静态 / 动态 Partition 的插入,支持 Overwrite 的插入。

  • 支持各种 Formats:

    • CSV

    • JSON

    • Aparch AVRO

    • Apache Parquet

    • Apache ORC

  • 支持 Batch 的读写。

  • 支持 Streaming sink,也支持 Partition commit,支持写 Success 文件。

 

用几句简单的 SQL,不用搭建 Hive 集成环境即可:

 

  • 启动一个流作业写入 Filesystem 中,然后在 Hive 端即可查询到 Filesystem 上的数据,相比之前 Datastream 的作业,简单 SQL 即可搞定离线数据的入库。

  • 通过 Filesystem Connector 来查询 Hive 数仓中的数据,功能没有 Hive 集成那么全,但是定义简单。

 

Table 易用性

 

■ DDL Hints 和 Like

 

 

在 Flink 1.10 以后,Hive MetaStore 逐渐成为 Flink streaming SQL 中 Table 相关的 Meta 信息的存储。比如,可以通过 Hive Catalog 保存 Kafka Tables。这样可以在启动的时候直接使用 Tables。

 

通过 DDL 这种方式,把 SQL 提交到 Cluster,就可以写入 Kafka,或者写入 MySQL、 DFS。使用 Hive Catalog 后,是不是说只用写一次 DDL,之后的流计算作业都是直接使用 Kafka 的 Table 呢?

 

不完全是,因为还是有一些缺陷。比如,一个典型的 Kafka Table 有一些 Execution 相关的参数。因为 kafka 一般来说都是存 15 天以内的数据,需要指定每次消费的时间偏移,时间偏移是在不断变化的。每次提交作业,使用 Kafka Table 的参数是不一样的。而这些参数又存储在 Catalog 里面,这种情况下只能创建另外一张表,所以字段和参数要重写一遍,非常繁琐。

 

  • Flink 1.11,社区就开发了 Table Hints,它在 1.11 中目前只专注一个功能,即 Dynamic Table Options。用起来很简单,在 SQL 中 Select From 时,在 Table 后面写 Table Hints 的方式来指定其动态 Options ,在不同的使用场景,指定不同的动态参数。

  • Flink 1.11,引入了 Like 语法。LIKE 是标准的 SQL 定义。相当于 Clone 一张表出来复用它的 schema。LIKE 支持多种 Constraints。可以选择继承,也可以选择完全覆盖。

 

Table Hints:

 

  •  
SELECT id, name FROM kafka_table1 /*+ OPTIONS('scan.startup.mode'='earliest-offset') */;

 

LIKE:

 

  •  
CREATE TABLE kafka_table2 WITH ( 'scan.startup.mode'='earliest-offset') LIKE kafka_table1;

 

这两个手段在对接 Hive Catalog 的基础上,是非常好的补充,能够尽可能的避免在每次作业的时候都写一大堆 Schema。

 

■ 内置 Connectors

 

Flink SQL 1.11 引入了新的三个内置 Connectors,主要是为了大家更方便的进行调试、测试,以及进行压测和线上的观察:

 

  • Datagen Source:一个无中生有产生数据的 Source,可以定义生成的策略,比如 Sequence,比如 Random 的生成。方便线下进行功能性的测试,也可以拿来性能测试。

  • Print Sink:直接在 Task 节点 Runtime 的打印出数据,比如线上作业某个 Sink 少数据了,不知道是上游发来数据有问题,还是 Sink 逻辑有问题,这时可以额外接一个 Print Sink,排查上游数据到底有没有问题。

  • Blackhole Sink:默默把数据给吃掉,方便功能性的调试。

 

这三个 Connectors 的目的是为了在调试、测试中排除 Connectors 的影响,一般来说,Connectors 在流计算中是不可控的存在,很多问题把 Connectors 糅杂在一起,变得比较复杂难以排查。

 

SQL-API

 

■ TableEnvironment

 

TableEnvironment 作为 SQL 层的编程入口,无疑是非常重要的,之前的 API 主要是:

 

  • Table sqlQuery:从一段 Select 的 Query 中返回 Table 接口,把用户的 SQL 翻译成 Flink 的 Table。

  • void sqlUpdate:本质上是执行一段 DDL/DML。但是行为上,当是 DDL 时,直接执行;当是 DML 时,默默 Cache 到 TableEnvironment,等到后续的 execute 调用,才会真正的执行。

  • execute:真正的执行,提交作业到集群。

 

TableEnvironment 默默的 Cache 执行计划,而且多个 API 感觉上会很混乱,所以,1.11 社区重构了编程接口,目的是想要提供一个干净、并且不易出 bug 的清晰接口。

 

  • 单 SQL 执行:TableResult executeSql(String sql)

  • 多 SQL 执行:StatementSet createStatementSet()

  • TableResult:支持 collect、print、getJobClient

 

现在 executeSql 就是一个大一统的接口,不管是什么 SQL,是 Query 还是 DDL 还是 DML,直接丢给它都可以很方便地使用起来。

 

并且,和 Datastream 也有了很清晰的界限:

 

  • 调用过 toDataStream:一定要使用 StreamExecutionEnvironment.execute

  • 没调用过 toDataStream:一定要使用 TableEnvironment.executeSql

 

■ SQL-Client

 

SQL-Client 在 1.11 对齐了很多 Flink 内部本来就支持的 DDL,除此之外值得注意的是,社区还开发了 Tableau 的结果展示模式,展示更自然一些,直接在命令行展示结果,而不是切换页面:

 

 

总结和展望

 

上述解读主要侧重在用户接口方面,社区已经有比较丰富的文档,大家可以去官网查看这些功能的详细文档,以便更深入的了解和使用。

 

Flink SQL 1.11 在 CDC 方面开了个头,内部机制和 API 上打下了夯实的基础,未来会内置更多的 CDC 支持,直接对接数据库 Binlog,支持更多的 Flink SQL 语法。后续版本也会从底层提供更多的流批一体支持,给 SQL 层带来更多的流批一体的可能性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flink 1.11 SQL 使用攻略 的相关文章

  • 将查询结果作为 CSV 文件从 Docker PostgreSQL 容器导出到本地计算机

    我不确定这是否可能 或者我是否做错了什么 因为我对 Docker 还很陌生 基本上 我想将 PostgreSQL docker 容器内的查询结果作为 csv 文件导出到本地计算机 这就是我到目前为止所得到的 首先 我使用以下命令运行 Pos
  • android-security :Google Play 警告:您的应用程序包含 SQL 注入问题

    作为我们应用程序的一部分 我们使用两个 contentProvider 但两者都受到 android exported false 的保护 但我们仍然收到一封 Google Play 警告邮件 您的应用程序包含 SQL 注入问题 他们提到的
  • MySQL select with 语句

    我正在学习更多 SQL 并遇到了一个 问题 我有两个表 如下面的链接http www sqlfiddle com 2 403d4 1 http www sqlfiddle com 2 403d4 1 编辑 由于我这个周末所做的所有 SQL
  • Bool类型返回规则

    我使用 dapper ORM 所以我使用两个规则Query
  • Mysql 更快的 INSERT

    好的 我有大约 175k 个 INSERT 语句 相当大的 INSERT 语句 例如 INSERT INTO gast ID Identiteitskaartnummer Naam Voornaam Adres Postcode Stad
  • 根据同一 select 语句中先前计算的行(或列)计算新行(或列)

    我正在尝试根据年度销售增长预期来计算年度预期销售量 在一张表中 我有实际销量 create table Sales ProductId int Year int GrowthRate float insert into Sales valu
  • 水晶报表参数选择有限制吗?

    我正在尝试根据按用户分组的 Oracle 数据库制作 Crystal Reports 11 报告 我有超过一千个用户 我想创建一个参数字段 提示用户选择他们想要查看其结果的用户 但是我的参数选择字段仅显示 221 个可能的用户 由于 SQL
  • 跨数据库管理系统检查字符串是否为数字的方法

    好的 我有这个字段 code varchar 255 它包含我们导出例程中使用的一些值 例如 DB84 DB34 3567 3568 我需要仅选择自动生成的 全数字 字段 WHERE is numeric table code is num
  • Oracle 时间戳数据类型

    不带参数的时间戳数据类型和带参数 0 的时间戳数据类型有什么不同 timestamp VS timestamp 0 括号中的数字指定要存储的小数秒的精度 所以 0 意味着不存储任何一小部分秒 而仅使用整秒 如果未指定 则默认值为小数点分隔符
  • Django 视图中的原始 SQL 查询

    我将如何使用原始 SQL 执行以下操作views py from app models import Picture def results request all Picture objects all yes Picture objec
  • 将 mysql 查询输出存储到 shell 变量中

    我需要一个变量来保存从数据库检索的结果 到目前为止 这基本上是我正在尝试但没有成功的事情 myvariable mysql database u user p password SELECT A B C FROM table a 正如你所看
  • 如何为不存在的值创建一行并用 0 值填充计数?

    在 SQL Server 中 我对数据上的用户年龄组运行查询 其中 在某些年里 每个年龄组的用户数为零 例如 2013 年有 18 21 年龄组的用户 因此查询返回下一个年龄组 22 25 作为第一行 因为没有包含 18 21 的条目 相反
  • 如何在 PostgreSQL 中生成月份列表?

    我有一张桌子A with startdate列是TIMESTAMP WITHOUT TIME ZONE我需要编写一个查询 函数来生成月份列表MIN列的值直到MAX列的值 例如 startdate 2014 12 08 2015 06 16
  • 了解 Oracle Apex_Application.G_Fnn 以及如何使用它

    我对 Oracle apex application gfnn 的工作原理以及它是否仅适用于 Oracle ApEx 中的标准 SQL 报告或仅适用于 SQL 可更新报告 即表格形式 感到非常困惑 基本上我试图使用这个示例 SQL 来实现以
  • Informix:带有输出参数的程序?

    我搜索了很多 但找不到任何东西 我只是想问是否有任何方法可以创建和调用过程 Informix 没有参数 我知道如何返回一个或多个值 对于过程和函数 但这不是我想要的 如果 Informix 不允许输出参数 那就真的很奇怪了 提前致谢 EDI
  • Oracle中表的列重新排序

    我有一个包含 50 多列的表 我需要交换前两列的顺序 使用 Oracle 实现此目的的最佳方法是什么 假设表名是 ORDERDETAILS 前两列是 ITEM ID 和 ORDER ID 重命名完成后 表名仍应为 ORDERDETAILS
  • 查找具有唯一两列组合的所有行

    我有这张桌子messages sender id recipient id 1 2 1 3 1 3 2 1 3 1 2 3 我希望选择这样的行 Either sender id or receiver id current user id
  • LEFT JOIN 返回与 INNER JOIN 相同的结果

    我有一张桌子 磨砂膏 里面有 1600 个独特的物品 第二张桌子有100万以上 我运行 INNER JOIN 并获得 65 个匹配项 SELECT a BW Parent Number a Vendor Name b Parent Supp
  • 帮助将二进制图像数据从 SQL Server 读取到 PHP 中

    我似乎无法找到将二进制数据从 SQL 服务器读取到 PHP 的方法 我正在开发一个项目 需要能够将图像直接存储在 SQL 表中 而不是文件系统上 目前 我一直在使用这样的查询 插入 myTable 文档 选择 从 OPENROWSET BU
  • 在旧版本的 MySQL (<5.5.0) 中模拟 TO_SECONDS()

    出于性能和简单性的原因 我想以秒的形式获取 MySQL 3 x 服务器中 DATETIME 列的内容 或者实际上任何数字类型 我只是想在使用 UNIX TIMESTAMP 时避免所有明显的时区问题 the我表中的日期确实来自不同的区域设置

随机推荐

  • 【极客日常】Go语言string、int、float、rune、byte等数据类型的转换方法

    golang的数据类型转换是困惑新gopher的一大问题之一 相对于python xff0c golang的数据类型转换可要麻烦的多 xff0c 而且还不走寻常路地诞生了些新的方法跟名词 因此本文讲解golang常见数据类型string i
  • View的mParent变量初始化

    mParent变量实际上是PhoneWindow DecorView类型 xff0c 是所有应用窗口的根视图 xff0c 是FrameLayout的子类 View的requestLayout 函数也是调用了mParent requestLa
  • java:N的N次方

    题目描述 现给你一个正整数N xff0c 请问N N的最左边的数字是什么 xff1f 输入格式 输入包含多组测试数据 每组输入一个正整数N xff08 N lt 61 1000000 xff09 输出 对于每组输入 xff0c 输出N N的
  • CentOS升级curl

    1 安装repo rpm Uvh http www city fan org ftp contrib yum repo rhel6 x86 64 city fan org release 2 1 rhel6 noarch rpm 2 查看该
  • ACM:入口的选择------深度优先搜索

    入口的选择 Time Limit 1000MS Memory Limit 32768K Description Zeism玩的赛车游戏中 xff0c 有一种树形的赛道 树根表示赛道的终点 xff0c 任何一个叶子结点表示一个赛道的入口 xf
  • ACM:n!的位数 :斯特林公式

    n 的位数 Time Limit 2000MS Memory Limit 65536K Description 针对每个非负整数n xff0c 计算其n 的位数 Input 输入数据中含有一些整数n xff08 0 n xff1c 10 7
  • java 自定义封装jdbc dao类

    手动封装jdbc和dao层 xff0c 体会其中的优点与不足 注 xff1a 本次采用的mysql数据库记得添加数据库的驱动包 Dbhelper类 xff1a 对jdbc进行封装 xff0c 采用单例模式 xff0c 不用每次都去连接数据库
  • Mybatis 二级缓存

    mybatis的缓存分为一级缓存和二级缓存 xff0c 缓存是用来缓存部分经常性访问的数据 xff0c 而不必每一次都跑到数据库获取或运算 xff0c 目标是提高系统的性能 一级缓存 对于每一个sqlSession 其中有一个HashMap
  • virtualbox启动报错:Interface VirtualBox Host-Only Ethernet Adapter is not a Host-Only Adapter interface

    参考 xff1a 参考 xff1a windows下VirtualBox使用过程中遇到的一个错误 报错信息 xff1a Interface 39 VirtualBox Host Only Ethernet Adapter 39 is not
  • Tried to access visual service WindowManager from a non-visual Context

    适配Android12时遇到的一个问题 xff0c 做个记录 xff1a 尝试使用WindowManager做一些事情的时候 xff0c 我们一般会先获取WindowManager的实例 xff0c 即 xff1a WindowManage
  • Electron使用electron-builder打包windows时如何签名

    windows打包基本配置 xff1a span class token string 34 build 34 span span class token operator span span class token punctuation
  • Electron打包mac OS安装包的配置和签名(干货)

    1 先看配置 xff08 electron vue xff09 打包使用的是electron builder package json span class token punctuation span span class token o
  • 【nodejs】exec在windows下读取中文乱码问题

    最近在做一个项目需求是读取计算机名称 在windows上使用nodejs exec读取时会有些电脑上会出现乱码问题 直接在cmd上执行hostname xff0c 返回的是没有问题的 当我使用exec读取时就乱码了 xff0c 虽然可以使用
  • 分享 :CSS常见面试题

    CSS基础 2 1 link和 64 import都可以为页面引入CSS文件 xff0c 其区别是 xff1f 将样式定义在单独的 css 的文件里 xff0c link 和 64 import 都可以在 html 页面引入 css 文件
  • Android LOG系统原理剖析

    引言 在我们android的开发过程中 xff0c 最不可少的就是加Log xff0c 打印Log的操作 这样可以帮助我们去查看各个变量 xff0c 理清楚代码的逻辑 而Android系统 xff0c 提供了不同维度 xff0c 不同层面
  • 分享:HTML常见面试题

    HTML基础 1 1请描述一个网页从开始请求到最终显示的完整过程 xff1f 一般可分为7个步骤 xff1a 1 在浏览器中输入网址 xff1b 2 发送至DNS服务器并获得域名对应的WEB服务器的IP地址 xff1b 3 与WEB服务器建
  • 使用NSAttributedString,添加删除线,中划线 链接

    常用的是其子类 xff1a NSMutableAttributedString 加中划线 xff0c 删除线的方法 xff1a lt pre name 61 34 code 34 class 61 34 objc 34 gt 获取要改变的字
  • 银河麒麟server v10 sp1 sshd报错:/usr/sbin/sshd:/lib64/libcrypt.so.1:version ‘XCRYPT_2.0’ not found

    目录 一 报错原因 二 报错内容 三 解决方法 一 报错原因 今天手工更新了glibc库 xff0c 结果导致sshd运行不了了 关于glibc的简单介绍 xff1a glibc是GNU发布的libc库 xff0c 即C运行库 glibc是
  • 银河麒麟V10 SP1桌面系统apt安装mysql 8后重置初始密码

    安装mysql sudo apt get install mysql server 重置初始密码 重置初始密码的原因是没有找到初始密码在哪里 xff0c mysql 8版本安全性更高 xff0c 初始密码不为空 配置skip grant t
  • Flink 1.11 SQL 使用攻略

    7 月 6 日 xff0c Apache Flink 1 11 正式发布 从 3 月初进行功能规划到 7 月初正式发版 xff0c 1 11 用将近 4 个月的时间重点优化了 Flink 的易用性问题 xff0c 提升用户的生产使用体验 S