pyflink学习笔记(一):table_apisql

news/2024/3/29 10:34:56/文章来源:https://blog.csdn.net/weixin_41907245/article/details/129175747
具体定义请参考官方文档:https://nightlies.apache.org/flink/flink-docs-release-1.16/zh/docs/dev/table/overview/
本文主要针对实际使用中比较常用的api进行整理,大多数例子都是官网,如有歧义可与官方对照。

一、 创建 TableEnvironment

TableEnvironment 是 Table API 和 SQL 的核心概念。它负责:

  • 在内部的 catalog 中注册 Table

  • 注册外部的 catalog

  • 加载可插拔模块

  • 执行 SQL 查询

  • 注册自定义函数 (scalar、table 或 aggregation)

  • DataStream 和 Table 之间的转换(面向 StreamTableEnvironment )

from pyflink.table import EnvironmentSettings, TableEnvironmentfrom pyflink.datastream import StreamExecutionEnvironment
from pyflink.table import StreamTableEnvironment
#创建流处理
env_settings = EnvironmentSettings.in_streaming_mode()
table_env = TableEnvironment.create(env_settings)
#创建批处理
env_settings = EnvironmentSettings.in_batch_mode()
table_env = TableEnvironment.create(env_settings)
#用户可以从现有的 StreamExecutionEnvironment 创建一个 StreamTableEnvironment 与 DataStream API 互操作。
s_env = StreamExecutionEnvironment.get_execution_environment()
t_env = StreamTableEnvironment.create(s_env)

TableEnvironment主要用来:

  • Table 管理:创建表、列举表、Table 和 DataStream 互转等。

  • 自定义函数管理:自定义函数的注册、删除、列举等。 关于 Python 自定义函数的更多细节,请参考普通自定义函数 和向量化自定义函数章节的介绍。

  • 执行 SQL 语句:更多细节可查阅SQL 查询章节的介绍。

  • 作业配置管理:更多细节可查阅Python 配置章节的介绍。

  • Python 依赖管理:更多细节可查阅依赖管理章节的介绍。

  • 作业提交:更多细节可查阅作业提交章节的介绍。

二、创建表

Table 是 Python Table API 的核心组件。Table 对象由一系列数据转换操作构成,但是它不包含数据本身。 相反,它描述了如何从数据源中读取数据,以及如何将最终结果写出到外部存储等。表可以被打印、优化并最终在集群中执行。 表也可以是有限流或无限流,以支持流式处理和批处理场景。

一个 Table 实例总是与一个特定的 TableEnvironment 相绑定。不支持在同一个查询中合并来自不同 TableEnvironments 的表,例如 join 或者 union 它们。

from pyflink.table import EnvironmentSettings, TableEnvironment# 创建 批 TableEnvironment
env_settings = EnvironmentSettings.in_batch_mode()
table_env = TableEnvironment.create(env_settings)

首先在上面创建了一个批处理的TableEnvironment。然后创建一张表。

在pyflink中,可从不同的数据类型中形成创建表,下面介绍几个比较常用的方法

1、from_elements

从元素集合创建表,集合中的元素必须长度相等,类型顺序相同

from_elements(elements: Iterable, schema: Union[pyflink.table.types.DataType, List[str]] = None, verify_schema: bool = True) → pyflink.table.table.Table

参数:

elements- 创建表格的元素。

schema- 表的架构。

verify_schema- 是否根据架构验证元素。

例子如下:schema可以使用DataTypes 指定类型,也可以不指定,直接写列名,会自动识别。

#table = table_env.from_elements([(1, 'Hi'), (2, 'Hello')],["a","b"])
#table = table_env.from_elements([(1, 'Hi'), (2, 'Hello')],DataTypes.ROW([DataTypes.FIELD("a", DataTypes.INT()),DataTypes.FIELD("b", DataTypes.STRING())]))
table.execute().print()

2、通过 pandas DataFrame 来创建表

from_pandas(pdf, schema=None, split_num=1)

参数:

  • pdf- Pandas DataFrame 。

  • schema- 转换后的表的架构。

  • splits_num- 给定的 Pandas DataFrame 将被分割成的分割数。它决定了并行源任务的数量。如果未指定,将使用默认并行度。

pdf = pd.DataFrame(np.random.rand(10, 2))
table = table_env.from_pandas(pdf, ["a", "b"])
#table_env.from_pandas(pdf, [DataTypes.DOUBLE(), DataTypes.DOUBLE()])
# table_env.from_pandas(pdf, DataTypes.ROW(
#     [DataTypes.FIELD("a", DataTypes.DOUBLE()), DataTypes.FIELD("b", DataTypes.DOUBLE())]))
table.execute().print()

3、create_temporary_view

通过指定路径下已注册的表来创建一个表,例如通过 create_temporary_view 注册表。

from_path(path: str) → pyflink.table.table.Table

参数:

path- 要扫描的表 API 对象的路径。

# 临时表
table = table_env.from_elements([(1, 'Hi'), (2, 'Hello')], ['id', 'data'])
table_env.create_temporary_view('source_table', table)
new_table = table_env.from_path('source_table')
new_table.execute().print()#读取表 - 从已注册的目录中读取表
table_env.execute_sql("""CREATE TABLE random_source (id BIGINT, data TINYINT ) WITH ('connector' = 'datagen','fields.id.kind'='sequence','fields.id.start'='1','fields.id.end'='3','fields.data.kind'='sequence','fields.data.start'='4','fields.data.end'='6')
""")
table = table_env.from_path("random_source")
table.execute().print()

create_temporary_view : 将一个 `Table` 对象注册为一张临时表,类似于 SQL 的临时表。

create_temporary_view(view_path, table)

参数:

  • view_path - 注册视图的路径。

  • table_or_data_stream用于创建视图的表或数据流。

table_env.execute_sql("""CREATE TABLE table_sink (id BIGINT, data VARCHAR ) WITH ('connector' = 'print')
""")# 将 Table API 表转换成 SQL 中的视图
table = table_env.from_elements([(1, 'Hi'), (2, 'Hello')], ['id', 'data'])
table_env.create_temporary_view('table_api_table', table)# 将 Table API 表的数据写入结果表
table_env.execute_sql("INSERT INTO table_sink SELECT * FROM table_api_table").wait()

4、execute_sql

执行指定的语句并返回执行结果。 执行语句可以是 DDL/DML/DQL/SHOW/DESCRIBE/EXPLAIN/USE。

注意,对于 "INSERT INTO" 语句,这是一个异步操作,通常在向远程集群提交作业时才需要使用。

execute_sql(stmt str)	

参数:

str- sql 语句

table_env.execute_sql("INSERT INTO table_sink SELECT * FROM table_api_table").wait()

5、sql_query(query)

执行一条 SQL 查询,并将查询的结果作为一个 `Table` 对象.

sql_query(query)	

参数:

query- sql 语句

table_env.sql_query("SELECT * FROM %s" % table)

6、create_statemente_set

用来执行多条sql语句,可以通过该方法编写multi_sink的作业。

table = table_env.from_elements([(1, 'Hi'), (2, 'Hello')], ['id', 'data'])
table_env.create_temporary_view("simple_source", table)
table_env.execute_sql("""CREATE TABLE first_sink_table (id BIGINT, data VARCHAR ) WITH ('connector' = 'print')
""")
table_env.execute_sql("""CREATE TABLE second_sink_table (id BIGINT, data VARCHAR) WITH ('connector' = 'print')
""")# 创建 statement set
statement_set = table_env.create_statement_set()# 将 "table" 的数据写入 "first_sink_table"
statement_set.add_insert("first_sink_table", table)# 通过一条 sql 插入语句将数据从 "simple_source" 写入到 "second_sink_table"
statement_set.add_insert_sql("INSERT INTO second_sink_table SELECT * FROM simple_source")# 执行 statement set
statement_set.execute().wait()

7> +I(1,Hi)

7> +I(1,Hi)

7> +I(2,Hello)

7> +I(2,Hello)

7、get_schema

获取schema信息

table = table_env.from_elements([(1, 'Hi'), (2, 'Hello')], ['id', 'data'])
# 默认情况下,“id” 列的类型是 64 位整型
print('By default the type of the "id" column is %s.' % table.get_schema().get_field_data_type("id"))from pyflink.table import DataTypestable = table_env.from_elements([(1, 'Hi'), (2, 'Hello')],DataTypes.ROW([DataTypes.FIELD("id", DataTypes.TINYINT()),DataTypes.FIELD("data", DataTypes.STRING())]))
# 现在 “id” 列的类型是 8 位整型
print(table.get_schema())

By default the type of the "id" column is BIGINT.

root

|-- id: TINYINT

|-- data: STRING

三、创建TableDescriptor

用来定义表的scheam

例子:

from pyflink.table import EnvironmentSettings, TableEnvironment, TableDescriptor, Schema, DataTypes# create a stream TableEnvironment
env_settings = EnvironmentSettings.in_streaming_mode()
table_env = TableEnvironment.create(env_settings)table_env.create_temporary_table('random_source',TableDescriptor.for_connector('datagen').schema(Schema.new_builder().column('id', DataTypes.BIGINT()).column('data', DataTypes.TINYINT()).build()).option('fields.id.kind', 'sequence').option('fields.id.start', '1').option('fields.id.end', '3').option('fields.data.kind', 'sequence').option('fields.data.start', '4').option('fields.data.end', '6').build())table = table_env.from_path("random_source")
table.execute().print()
+----+----------------------+--------+
| op |                   id |   data |
+----+----------------------+--------+
| +I |                    1 |      4 |
| +I |                    2 |      5 |
| +I |                    3 |      6 |
+----+----------------------+--------+

for_connector:使用给定的连接器为表创建一个新的构建器

参数:

当前仅有部分 connector 的实现包含在 Flink 官方提供的发行包中,好比 FileSystem,DataGen、Print、BlackHole 等,大部分 connector 的实现当前没有包含在 Flink 官方提供的发行包中,好比 Kafka、ES 等。针对没有包含在 Flink 官方提供的发行包中的 connector,若是须要在 PyFlink 做业中使用,用户须要显式地指定相应 FAT JAR.

具体直接看阿里云的flink文档:https://help.aliyun.com/document_detail/176688.html

四、在 Catalog 中创建表

表可以是临时的,并与单个 Flink 会话(session)的生命周期相关,也可以是永久的,并且在多个 Flink 会话和群集(cluster)中可见。

永久表需要 catalog(例如 Hive Metastore)以维护表的元数据。一旦永久表被创建,它将对任何连接到 catalog 的 Flink 会话可见且持续存在,直至被明确删除。

通过 SQL DDL 创建的表和视图, 例如 “create table …” 和 “create view …",都存储在 catalog 中。

你可以通过 SQL 直接访问 catalog 中的表。

如果你要用 Table API 来使用 catalog 中的表,可以使用 “from_path” 方法来创建 Table API 对象:

# 准备 catalog
# 将 Table API 表注册到 catalog 中
table = table_env.from_elements([(1, 'Hi'), (2, 'Hello')], ['id', 'data'])
table_env.create_temporary_view('source_table', table)# 从 catalog 中获取 Table API 表
new_table = table_env.from_path('source_table')
new_table.execute().print()
+----+----------------------+--------------------------------+
| op |                   id |                           data |
+----+----------------------+--------------------------------+
| +I |                    1 |                             Hi |
| +I |                    2 |                          Hello |
+----+----------------------+--------------------------------+

五、Table API-DML语法

from pyflink.table import EnvironmentSettings, TableEnvironment
from pyflink.table.expressions import col
from pyflink.table.expressions import concat# 通过 batch table environment 来执行查询
env_settings = EnvironmentSettings.in_batch_mode()
table_env = TableEnvironment.create(env_settings)orders = table_env.from_elements([('Jack', 'FRANCE', 10), ('Rose', 'ENGLAND', 30), ('Jack', 'FRANCE', 20)],['name', 'country', 'revenue'])

1.查询-select


# 查询两列
revenue = orders.select(col("name"), col("country").alias('country')) 
# 查询全部列
revenue1 = orders .select(col("*")) revenue.execute().print()
table_result = revenue.execute()
print(type(table_result ))
+--------------------------------+--------------------------------+
|                           name |                        country |
+--------------------------------+--------------------------------+
|                           Jack |                         FRANCE |
|                           Rose |                        ENGLAND |
|                           Jack |                         FRANCE |
|                            Bob |                             CH |
|                            Bob |                             CH |
|                             YU |                             CH |
+--------------------------------+--------------------------------

<class 'pyflink.table.table_result.TableResult'>

说下返回值,通过打印可以知道revenue.execute()返回值类型是TableResult,这个类型不能直接通过for循环遍历。

需要调用collect()方法,然后在遍历。

for res_row in table_result.collect():for rr in res_row:print(rr)

对于 SELECT 操作,除非已收集所有结果数据,否则作业不会完成,所以除非是有界或是批处理,那么不建议使用for循环遍历数据。

#所以建立使用with循环
with table_result.collect() as results:for result in results:

2.过滤-where

等同filter,和 SQL 的 WHERE 子句类似。 过滤掉未验证通过过滤谓词的行。

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

result = orders.where(col("name") == 'Jack')
#或
result = orders.filter(col("name") == 'Jack')
#打印
result .execute().print()
+--------------------------------+--------------------------------+-------------+-------------------------+
|                           name |                        country |     revenue |                  r_time |
+--------------------------------+--------------------------------+-------------+-------------------------+
|                           Jack |                         FRANCE |          10 | 2023-02-23 11:11:33.081 |
|                           Jack |                         FRANCE |          20 | 2023-02-24 07:11:33.081 |
+--------------------------------+--------------------------------+-------------+-------------------------+

3.列操作

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

#添加列,add_columns但是如果该列存在则直接报错
#concat 合并
result = orders.add_columns(concat(col("name"), 'sunny').alias('desc'))
result .execute().print()
+--------------------------------+--------------------------------+-------------+-------------------------+--------------------------------+
|                           name |                        country |     revenue |                  r_time |                           desc |
+--------------------------------+--------------------------------+-------------+-------------------------+--------------------------------+
|                           Jack |                         FRANCE |          10 | 2023-02-23 11:11:33.081 |                      Jacksunny |
|                           Rose |                        ENGLAND |          30 | 2023-02-23 21:11:33.081 |                      Rosesunny |
|                           Jack |                         FRANCE |          20 | 2023-02-24 07:11:33.081 |                      Jacksunny |
|                            Bob |                             CH |          40 | 2023-02-24 17:11:33.081 |                       Bobsunny |
|                            Bob |                             CH |          50 | 2023-02-24 17:11:33.081 |                       Bobsunny |
|                             YU |                             CH |         100 | 2023-02-23 14:11:33.081 |                        YUsunny |
+--------------------------------+--------------------------------+-------------+-------------------------+--------------------------------+
#add_or_replace_columns:执行字段添加操作。 如果添加的列名称和已存在的列名称相同,则已存在的字段将被替换。 此外,如果添加的字段里面有重复的字段名,则会使用最后一个字段。
result = orders.add_or_replace_columns(concat(col("name"), 'sunny').alias('desc')).select(col("name"),col("desc"))
result.execute().print()
+--------------------------------+--------------------------------+
|                           name |                           desc |
+--------------------------------+--------------------------------+
|                           Jack |                      Jacksunny |
|                           Rose |                      Rosesunny |
|                           Jack |                      Jacksunny |
|                            Bob |                       Bobsunny |
|                            Bob |                       Bobsunny |
|                             YU |                        YUsunny |
+--------------------------------+--------------------------------+
#删除列,如果删除多个,则用逗号隔开,drop_columns(col("a"),col("b"))
result = orders.drop_columns(col("name"))
result.execute().print()
+--------------------------------+-------------+-------------------------+
|                        country |     revenue |                  r_time |
+--------------------------------+-------------+-------------------------+
|                         FRANCE |          10 | 2023-02-23 11:11:33.081 |
|                        ENGLAND |          30 | 2023-02-23 21:11:33.081 |
|                         FRANCE |          20 | 2023-02-24 07:11:33.081 |
|                             CH |          40 | 2023-02-24 17:11:33.081 |
|                             CH |          50 | 2023-02-24 17:11:33.081 |
|                             CH |         100 | 2023-02-23 14:11:33.081 |
+--------------------------------+-------------+-------------------------+
#修改列名
result = orders.rename_columns(col("name").alias('name1'), col("country").alias('country2'))
result.execute().print()
+--------------------------------+--------------------------------+-------------+-------------------------+
|                          name1 |                       country2 |     revenue |                  r_time |
+--------------------------------+--------------------------------+-------------+-------------------------+
|                           Jack |                         FRANCE |          10 | 2023-02-23 11:11:33.081 |
|                           Rose |                        ENGLAND |          30 | 2023-02-23 21:11:33.081 |
|                           Jack |                         FRANCE |          20 | 2023-02-24 07:11:33.081 |
|                            Bob |                             CH |          40 | 2023-02-24 17:11:33.081 |
|                            Bob |                             CH |          50 | 2023-02-24 17:11:33.081 |
|                             YU |                             CH |         100 | 2023-02-23 14:11:33.081 |
+--------------------------------+--------------------------------+-------------+-------------------------+

4.聚合计算-Aggregations

4.1 group_by

# 计算所有来自法国客户的收入
# 使用group_by 来进行分组计算
#对于流失计算,因为数据是无界的,计算出的结果是可能是无限长的,取决查询或聚合的字段,所以当是流式时,请提供空闲状态保留时间。
revenue = orders \.select(col("name"), col("country"), col("revenue")) \.where(col("country") == 'FRANCE') \.group_by(col("name")) \.select(col("name"), orders.revenue.sum.alias('rev_sum'))revenue.execute().print()
+--------------------------------+-------------+
|                           name |     rev_sum |
+--------------------------------+-------------+
|                           Jack |          30 |
+--------------------------------+-------------+

4.2窗口函数 - Tumble

滚动窗口将行分配给固定长度的非重叠连续窗口。例如,一个 5 分钟的滚动窗口以 5 分钟的间隔对行进行分组。滚动窗口可以定义在事件时间、处理时间或行数上。

#生成测试数据
orders = table_env.from_elements(
[
('Jack', 'FRANCE', 10, datetime.now()+timedelta(hours=2)),
('Rose', 'ENGLAND', 30, datetime.now()+timedelta(hours=12)),
('Jack', 'FRANCE', 20, datetime.now()+timedelta(hours=22)),
('Bob', 'CH', 40, datetime.now()+timedelta(hours=32)),
('Bob', 'CH', 50, datetime.now()+timedelta(hours=32)),
('YU', 'CH', 100, datetime.now()+timedelta(hours=5))
],
DataTypes.ROW([DataTypes.FIELD("name", DataTypes.STRING()),
DataTypes.FIELD("country", DataTypes.STRING()),
DataTypes.FIELD("revenue", DataTypes.INT()),
DataTypes.FIELD("r_time", DataTypes.TIMESTAMP(3))]))
#设置窗口函数
win_fun= Tumble.over(lit(1).hours).on(col('r_time')).alias("w")

over

将窗口的长度定义为时间或行计数间隔。

on

要对数据进行分组(时间间隔)或排序(行计数)的时间属性。批处理查询支持任意 Long 或 Timestamp 类型的属性。流处理查询仅支持声明的事件时间或处理时间属性。

alias

指定窗口的别名。别名用于在 group_by() 子句中引用窗口,并可以在 select() 子句中选择如窗口开始、结束或行时间戳的窗口属性。

#使用窗口函数
result = orders.window(win_fun) \.group_by(col('name'), col('w')) \.select(col('name'), col('w').start, col('w').end, col('revenue').sum.alias('d')).order_by("d")
result.execute().print()
+--------------------------------+-------------------------+-------------------------+-------------+
|                           name |                  EXPR$0 |                  EXPR$1 |           d |
+--------------------------------+-------------------------+-------------------------+-------------+
|                           Jack | 2023-02-22 19:00:00.000 | 2023-02-22 20:00:00.000 |          10 |
|                           Jack | 2023-02-23 15:00:00.000 | 2023-02-23 16:00:00.000 |          20 |
|                           Rose | 2023-02-23 05:00:00.000 | 2023-02-23 06:00:00.000 |          30 |
|                            Bob | 2023-02-24 01:00:00.000 | 2023-02-24 02:00:00.000 |          90 |
|                             YU | 2023-02-22 22:00:00.000 | 2023-02-22 23:00:00.000 |         100 |
+--------------------------------+-------------------------+-------------------------+-------------+

4.3窗口函数 - Over Window

和 SQL 的 OVER 子句类似 PS:暂时没有测试数据,参考sql即可

Over.partition_by(col("a")) \ .order_by(col("rowtime")) \ .preceding(expr.UNBOUNDED_RANGE) \ .alias("w")

order_by 需是time 属性才可以排序

4.4Distinct Aggregation

和 SQL DISTINCT 聚合子句类似,例如 COUNT(DISTINCT a)。

#去重后相加
group_by_distinct_result = orders.group_by(col("name")) \.select(col("name"), col("revenue").sum.distinct.alias('d'))
group_by_distinct_result .execute().print()
+--------------------------------+-------------+
|                           name |           d |
+--------------------------------+-------------+
|                           Jack |          30 |
|                            Bob |          90 |
|                             YU |         100 |
|                           Rose |          30 |
+--------------------------------+-------------+

也可以直接Distinct,筛选完全相同的行数据。

orders1 = table_env.from_elements([('Jack', 'FRANCE', 10),('Jack', 'FRANCE', 10)],DataTypes.ROW([DataTypes.FIELD("name", DataTypes.STRING()), DataTypes.FIELD("country", DataTypes.STRING()),DataTypes.FIELD("revenue", DataTypes.INT())]))
result = orders1.distinct()
result .execute().print()
+--------------------------------+--------------------------------+-------------+
|                           name |                        country |     revenue |
+--------------------------------+--------------------------------+-------------+
|                           Jack |                         FRANCE |          10 |
+--------------------------------+--------------------------------+-------------+

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_72920.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode之消失的数字轮转数组

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录一、消失的数字一、消失的数字 二、旋转数组 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、消失的数字 这题找出消失的一个数字&#…

(二十三)、实现评论功能(3)【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】

1&#xff0c;删除评论的样式和实现逻辑 1.1 添加删除评论的样式 在comment-item组件中&#xff1a; <view class"username">{{giveName(item)}}<text class"iconfont icon-a-43-guanbi" click.stop"delComment"></text><…

【总结】python3启动web服务引发的一系列问题

背景 在某行的实施项目&#xff0c;需要使用python3环境运行某些py脚本。 由于行内交付的机器已自带python3 &#xff0c;没有采取自行安装python3&#xff0c;但是运行python脚本时报没有tornado module。 错误信息 ModuleNotFoundError&#xff1a;No module named ‘torn…

计算机网络第3章(数据链路层)学习笔记

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

JVM面试总结

文章目录栈帧中存放的信息&#xff1a;对象的创建过程对象的内存布局&#xff1f;对象的访问定位方式&#xff1f;如何判断对象已死&#xff1f;可以作为GC Root的点&#xff1a;谈一下引用对象再被回收时如何逃脱&#xff1f;回收方法区如何判断常量是否废弃&#xff1f;垃圾回…

Redis的安装部署和配置文件的修改

1、准备安装环境 由于 Redis 是基于 C 语言编写的&#xff0c;因此首先需要安装 Redis 所需要的依赖&#xff1a; yum install -y gcc tcl gcc-c make 2、上传安装文件 将下载好的 redis-6.2.7.tar.gz 安装包上传到虚拟机的任意目录&#xff08;一般推荐上传到 /usr/local/s…

Mysql 索引(三)—— 不同索引的创建方式(主键索引、普通索引、唯一键索引)

了解了主键索引的底层原理&#xff0c;主键索引其实就是根据主键字段建立相关的数据结构&#xff08;B树&#xff09;&#xff0c;此后在使用主键字段作为条件查询时&#xff0c;会直接根据主键查找B树的叶子结点。除了主键索引外&#xff0c;普通索引和唯一键索引也是如此&…

stm32f103封装 入门教学(一)LED程序CubeMX

本文代码使用 HAL 库。 文章目录前言一、LED 原理图二、CubeMX创建工程三、LED 相关函数1. 输出电平函数&#xff1a;2. 延时函数&#xff1a;3. 翻转电平函数&#xff1a;四、详细代码实验现象 &#xff1a;总结代码 源码&#xff1a;前言 从这篇文章开始&#xff0c;我们讲解…

了解Axios及其运用方式

Axios简介 axios框架全称&#xff08;ajax – I/O – system&#xff09;&#xff1a; 基于promise用于浏览器和node.js的http客户端&#xff0c;因此可以使用Promise API 一、axios是干啥的 说到axios我们就不得不说下Ajax。在旧浏览器页面在向服务器请求数据时&#xff0c;…

醒醒吧,外包测试哪有前途,你只是一块干电池而已,随时会被替换掉

我25岁的时候&#xff0c;外包测试&#xff0c;薪资13.5k&#xff0c;人在深圳。 内卷什么的就不说了&#xff0c;而且人在外包那些高级精英年薪大几十的咱也接触不到&#xff0c;就说说外包吧。假设以我为界限&#xff0c;25岁一线城市13.5k&#xff0c;那22-24大部分情况下是…

URP渲染管线光照机制剖析

上一节通过剖析URP 摄像机了解摄像机的机制&#xff0c;本节来分析URP的光照的主要机制&#xff0c;并通过与内置的向前渲染管线做对比&#xff0c;来比较它们的与不同。 对啦&#xff01;这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白&#xff0c;也有一些…

小程序电商商城怎么搭建?

做电商的企业商家都会首先搭建好自己的电商商城&#xff0c;尤其是现在小程序盛行的时代&#xff0c;小程序电商商城更是做电商的企业商家的必备媒介。那么小程序电商商城怎么搭建&#xff1f;下面给大家说说一些流程作为参考。 一、准备事项 搭建小程序电商商城&#xff0c;…

打不过就拉拢!ChatGPT和MidJourney已经成我小秘书!太爽了

大家好&#xff0c;我是晓衡。这两周&#xff0c;我战斗力爆棚了&#xff01;每天大概睡了四~五个小时&#xff0c;而且中午也没有休息过&#xff0c;但精神却还很亢奋。直到周一下午&#xff0c;身体才有种被掏空的感觉&#xff0c;晚上 10 点就睡了。可能是兴奋劲还在&#x…

git 的使用方法(上 - 指令)

目录前言&#xff1a;一、Git 是什么&#xff1f;二、SVN与Git的最主要的区别&#xff1f;三、Git 安装四、git 配置1. 创建仓库 - repository2. 配置3. 工作流与基本操作五、Git 的使用流程1. 仓库中创建 1.txt文件2. 查看工作区的文件状态3. 添加工作区文件到暂存区4. 创建版…

蓝桥杯:聪明的猴子

题目链接&#xff1a;聪明的猴子https://www.lanqiao.cn/problems/862/learning/ 目录 题目描述 输入描述 输出描述 输入输出样例 运行限制 解题思路&#xff1a; 最小生成树 AC代码&#xff08;Java&#xff09;: 课后练习&#xff1a; 题目描述 在一个热带雨林中生存…

C++11 条件变量(condition_variable)

一、总述 在C11中&#xff0c;我们可以使用条件变量&#xff08;condition_variable&#xff09;实现多个线程间的同步操作&#xff1b;当条件不满足时&#xff0c;相关线程被一直阻塞&#xff0c;直到某种条件出现&#xff0c;这些线程才会被唤醒。 主要成员函数如下&#x…

【java】Spring Cloud --Spring Cloud Alibaba 微服务解决方案

文章目录1、Spring Cloud Alibaba 是什么先说说 Spring CloudSpring Cloud Alibaba和Spring Cloud 的区别和联系Spring Cloud Alibaba2、Spring Cloud Alibaba 包含组件阿里开源组件阿里商业化组件集成 Spring Cloud 组件3、Spring Cloud Alibaba 功能服务注册与发现支持多协议…

教你如何搭建培训机构-学员管理系统,demo可分享

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建培训机构-学员管理。1.2、应用场景学员信息报表展示所有正式学员信息&#xff0c;可对学员进行分配班级、转课、续课、扩科、退课、阶段测评等操作。2、设置方法2.1、表单搭建1&#xff09;新建表单【学员】&#xff0c;字段…

和日期相关的代码和bug——一道力扣题中的小发现

目录 Day of the Week 题目大意 常规方法 Python代码 Golang代码 C代码 基姆拉尔森公式 Python代码 Golang代码 C代码 使用库函数 Python代码 Golang代码 C代码 Day of the Week Given a date, return the corresponding day of the week for that date. The inp…

微信协议网页版微信协议解析

最近在做个微信机器人&#xff0c;所以研究了网页版的微信协议及相关接口&#xff0c;在这里简单总结一下。从表面上看&#xff0c;对于网页版微信我们的使用流程是这样的&#xff1a;很简单&#xff0c;只有四步&#xff0c;但如果细化到内里细节的话&#xff0c;上面这简单四…