当前位置: 首页 > article >正文

PostgreSQL10 逻辑复制实战:构建高可用数据同步架构!

PostgreSQL10 逻辑复制实战:打造高可用数据同步架构!

概述

PostgreSQL 10 引入了逻辑复制(Logical Replication),为数据库高可用和数据同步提供了更灵活的选择。PostgreSQL 复制机制主要分为物理复制和逻辑复制两种:物理复制(又称流复制/物理块复制)在实例级别同步数据,而逻辑复制则支持更精细的复制粒度。逻辑复制通过逻辑解码插件解析 WAL 日志,提取 DML 语句并在订阅端执行,从而实现表级别的数据同步,适用于分库分表、实时数据同步、异构数据同步等高可用场景。

具备特性

逻辑复制过程中使用限制:

1. 不支持复制DDL。
2. 不支持复制序列、索引。
3. 不支持双向复制。
4. 发布节点和订阅节点表的模式名、表名必须一致,订阅节点允许表有额外字段。

逻辑复制与物理复制区别:

1. 物理复制不能垮操作系统(Linux-Windows),而逻辑复制可以。
2. 无法在不同的PG版本之间进行物理复制(例如10-12),逻辑复制可以支持。因此PostgreSQL大版本升级可以使用逻辑复制。
3. 物理复制是实例级别的复制,而逻辑复制可以基于对象级别(具体到某个表)。
4. 物理复制备库只能读,逻辑复制的备库可以写入。

应用场景

可基于表级别复制,是一种粒度可细的复制,主要用在以下场景

1. 满足业务上需求,实现某些指定表数据同步。
2. PostgreSQL 跨版本数据同步。
3. PostgreSQL 大版本升级。

具体流程

逻辑复制的流程图

在这里插入图片描述

PostgreSQL数据库逻辑复制使用发布者/订阅者模型,使用订阅复制槽技术,可并行的传输WAL日志,通过在订阅端回放WAL日志中的逻辑条目,保持复制表的数据同步,订阅端通过逻辑解码对数据进行REDO。

PUBLICATION对象

CREATE PUBLICATION 名称
[ FOR TABLE [ ONLY ] 表名 [ * ] [, ...]
| FOR ALL TABLES ]
[ WITH ( publication_parameter [= 值] [, ... ] ) ]

参数说明

FOR TABLE:表示要复制的表,可以通过’,’定义多个表。
FOR ALL TABLES:表示数据库的所有表都要复制。
WITH:表的DML操作行为,忽略表示全部DML操作。

一个PUBLICATION对象可以注册一个或多个表,也可以选择DML操作进行复制,一个表同时也可以被多个PUBLICATION注册。

SUBSCRIPTION对象

CREATE SUBSCRIPTION subscription_name
CONNECTION 'conninfo'
PUBLICATION publication_name [, ...]
[ WITH ( subscription_parameter [= 值] [, ... ] ) ]

参数说明

CONNECTION:连接master节点的字符串信息。eg. 'host=ip port=5432 user=xxx dbname=xxx'
PUBLICATION:对应发布端的PUBLICATION对象
WITH:表示DML操作,忽略表示全部DML操作

SUBSCRIPTION对象是逻辑复制过程汇总,由订阅节点创建的对象,用于连接发布节点的PUBLICATION对象。

逻辑解码

逻辑解码是使用一个输出插件将 Postgres 的预写日志 (WAL) 转换为可读格式。逻辑解码过程如图:

在这里插入图片描述

当 Postgres 数据库表中的一行发生更改时,该更改会记录在 WAL 中。如果启用了逻辑解码,则该更改的记录将传递给输出插件。输出插件将记录从 WAL 格式更改为插件的格式(例如 JSON 对象)。然后重新格式化的更改通过复制槽退出 Postgres。最后是消费者。消费者是您选择的任何连接到 Postgres 并接收逻辑解码输出的应用程序。

pgout插件解码wal后效果:

testdb=# select * from pg_logical_slot_get_changes('test', pg_current_wal_lsn(), 10); lsn     |  xid   |                                                 data                                                 
------------+--------+------------------------------------------------------------------------------------------------------0/3DAE5178 | 377183 | BEGIN 3771830/3DAE5178 | 377183 | table public.users: UPDATE: id[character varying]:'4' name[character varying]:'anna' age[integer]:210/3DAE5348 | 377183 | COMMIT 3771830/3DAE65F0 | 377184 | BEGIN 3771840/3DAE65F0 | 377184 | table public.users: INSERT: id[character varying]:'5' name[character varying]:'5' age[integer]:550/3DAE6728 | 377184 | COMMIT 377184
(6 rows)

wal2json 插件可解码为json格式。

https://docs.microsoft.com/zh-cn/azure/postgresql/concepts-logical

使用示例

测试构建PostgreSQL10的逻辑复制环境。

角色数据库操作系统版本和数据库版本复制用户
发布节点:172.168.98.107testdbCentos 7/ PostgreSQL 10replication
订阅节点:172.168.98.115testdbCentos 7/ PostgreSQL 10replication

1、首先需要在发布角色节点设置 postgresql.conf 相关参数。

wal_level = logical

2、配置主和复制节点的pg_hba.conf文件配置replication用户连接不受限

host replication all 0.0.0.0/0 trust

3、主库和复制库上都创建replication角色并具有复制权限

[root@localhost ~]# su postgres
bash-4.2$ psql
postgres=# CREATE ROLE replication WITH replication PASSWORD '123456' LOGIN;

4、主库和复制库上都创建测试库和测试表

postgres=# CREATE USER testdb WITH ENCRYPTED PASSWORD 'testdb!123';
postgres=# CREATE DATABASE testdb OWNER testdb;

执行\c命令切换至testdb数据库

postgres=# \c testdb testdb
You are now connected to database "testdb" as user "testdb".
testdb=>

继续执行创建测试表

CREATE TABLE users (id varchar(10) NOT NULL,name varchar(35) NOT NULL,age integer
) ;
ALTER TABLE public.users ADD CONSTRAINT users_id_pkey PRIMARY KEY ("id");

主库插入测试数据

INSERT INTO public.users (id, name, age) VALUES ('1', 'zhangsan', 20);
INSERT INTO public.users (id, name, age) VALUES ('2', 'lisi', 30);
INSERT INTO public.users (id, name, age) VALUES ('3', 'wangwu', 21);

5、主库和复制库上都给replication用户授权数据库权限

testdb=> GRANT SELECT ON ALL tables IN SCHEMA PUBLIC TO replication;

6、在主库上创建发布并指定users表

testdb=> CREATE PUBLICATION testpub FOR TABLE users;
CREATE PUBLICATION
testdb=> \dRpList of publicationsName   | Owner  | All tables | Inserts | Updates | Deletes 
---------+--------+------------+---------+---------+---------testpub | testdb | f          | t       | t       | t
(1 row)testdb=>

7、在复制库上创建订阅

创建订阅,指定连接到主库上的发布。使用superuser来创建订阅,通过命令\c切换至postgres用户。

testdb=> \c testdb postgres
You are now connected to database "testdb" as user "postgres".
testdb=# CREATE SUBSCRIPTION testsub CONNECTION 'host=172.168.98.107 port=5432 dbname=testdb user=replication password=123456' PUBLICATION testpub;
NOTICE:  created replication slot "testsub" on publisher
CREATE SUBSCRIPTION

创建订阅时可指定已经存在的slot

CREATE SUBSCRIPTION testsub CONNECTION 'host=172.168.98.107 port=5432 dbname=testdb user=replication password=123456' PUBLICATION testpub WITH (slot_name=test, create_slot=false);

复制库上面查看订阅情况

testdb=# \dRsList of subscriptionsName   |  Owner   | Enabled | Publication 
---------+----------+---------+-------------testsub | postgres | t       | {testpub}
(1 row)

创建成功之后数据会自动复制过来。

testdb=# SELECT * FROM users;id |   name   | age 
----+----------+-----1  | zhangsan |  202  | lisi     |  303  | wangwu   |  21(3 rows)

8、测试增删改

-- 主库插入记录
testdb=> INSERT INTO users VALUES('4','anna', 17);
INSERT 0 1-- 从库查询,记录'anna'已插入。
testdb=> select * from users;id |   name   | age 
----+----------+-----1  | zhangsan |  202  | lisi     |  303  | wangwu   |  214  | anna     |  17
(4 rows)-- 主库修改'anna'
testdb=> update users set age=18 where id='4';
-- 从库查询'anna'age已经同步修改...-- 主库删除'anna'
testdb=> delete from users where id='4';
-- 从库查询'anna'这行数据同步删除...

常用命令

查看当前数据库已有发布

SELECT * FROM pg_publication;

查看当前数据库已有订阅

SELECT * FROM pg_subscription;

删除发布

DROP PUBLICATION testpub;

删除订阅

DROP SUBSCRIPTION testsub;

禁用订阅

ALTER SUBSCRIPTION testsub disable;

启动订阅

ALTER SUBSCRIPTION testsub enable;

如果逻辑复制操作中一张表缺少主键,就需要执行这条语句,代表使用整行作为标识

ALTER TABLE table REPLICA IDENTITY FULL;

解除复制槽与订阅的关联

ALTER SUBSCRIPTION testsub disable;
ALTER SUBSCRIPTION testsub SET (slot_name = NONE);
DROP SUBSCRIPTION testsub;

显示当前服务的所有复制连接(发布端执行)

SELECT * FROM pg_stat_replication;

显示订阅者的状态信息

SELECT * FROM pg_stat_subscription;

显示所有复制槽(发布端执行)

SELECT * FROM pg_replication_slots;

创建复制槽

select pg_create_logical_replication_slot('test','test_decoding');

创建复制槽

SELECT pg_create_logical_replication_slot('sub_iuser', 'pgoutput');

在这个示例中:

  • ‘sub_iuser’ 是要创建的复制槽的名称。
  • ‘pgoutput’ 是指定的输出插件名称,它用于将逻辑复制的 WAL 记录转换为适合于逻辑复制的格式。

执行上述 SQL 命令后,将创建名为 sub_iuser 的逻辑复制槽。

请确保在创建复制槽之前,已经启用了逻辑复制,并且已经将逻辑复制参数配置为允许创建复制槽。

删除复制槽

SELECT * FROM pg_drop_replication_slot('test');

脚本实践

使用脚本发布订阅相关数据库和相关表

逻辑复制发布脚本

#!/bin/sh# DB密码
PASSWORD=PG_PWD
# 查询所有数据库
database_name_result=$(PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "
SELECT d.datname AS database_name FROM pg_database d JOIN pg_user u ON d.datdba = u.usesysid WHERE u.usename = 'iuser';")
if [ -z "$database_name_result" ]; then# 查询结果为空exit 1
fiwhile IFS= read -r database_name; dodatabase_name=$(echo "$database_name" | sed 's/ //g')# 删除可能存在的发布、订阅关系PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "DROP PUBLICATION IF EXISTS pub_$database_name;"PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "DROP SUBSCRIPTION IF EXISTS sub_$database_name;"# 重新创建发布关系table_names=""# 主备需要排除表(例如排除日志表)table_names=$(PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "SELECT string_agg(table_name, ',') AS table_namesFROM information_schema.tablesWHERE table_schema = 'public'AND table_type = 'BASE TABLE'AND table_name NOT LIKE 't_log%'AND table_name != 't_xxx';")# 获取要发布的表清单信息PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "CREATE PUBLICATION pub_$database_name FOR TABLE $table_names;"PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "SELECT * FROM pg_publication;"echo "PUBLICATION $database_name done."
echo "PUBLICATION done."

逻辑复制订阅脚本

注意:需要传参主库服务器ip和主库数据库密码。

#!/bin/sh
# 主机
MASTER_HOST=$1
# 主机数据库密码
MASTER_PASSWORD=$2
# 当前备机旧密码
PASSWORD=PG_PWD
# 查询iuser用户下的所有数据库
database_name_result=$(PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "
SELECT d.datname AS database_name FROM pg_database d JOIN pg_user u ON d.datdba = u.usesysid WHERE u.usename = 'iuser';")
if [ -z "$database_name_result" ]; then
# 查询结果为空exit 1
fi
# 遍历每个数据库
while IFS= read -r database_name; dodatabase_name=$(echo "$database_name" | sed 's/ //g')# 删除存在的发布、订阅关系PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "DROP PUBLICATION IF EXISTS pub_$database_name;"PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "DROP SUBSCRIPTION IF EXISTS sub_$database_name;"# 尝试连接数据库echo "尝试连接主机数据库[$database_name]..."PGPASSWORD=$MASTER_PASSWORD psql -h $MASTER_HOST -p 5432 -U iuser -d $database_name -c "SELECT 1;"if [ $? -eq 0 ]; thenecho "主机数据库连接[$database_name]成功..."elseecho "主机数据库连接[$database_name]失败..."continuefi# 清空表数据# 主备需要排除表(例如排除日志表)table_name_result=$(PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "SELECT table_nameFROM information_schema.tablesWHERE table_schema = 'public'AND table_type = 'BASE TABLE'AND table_name NOT LIKE 't_log%'AND table_name != 't_xxx';")while IFS= read -r table_name; doecho "Processing table: $table_name"# 清空表数据PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "TRUNCATE TABLE $table_name;"# 重新创建订阅关系PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "CREATE SUBSCRIPTION sub_$database_nameCONNECTION 'host=$MASTER_HOST port=5432 user=iuser password=$MASTER_PASSWORD dbname=$database_name'PUBLICATION pub_$database_name;"# 查询订阅情况echo "SELECT SUBSCRIPTION"PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "SELECT * FROM pg_subscription;"echo "SUBSCRIPTION $database_name done."
done <<< "$database_name_result"
echo "SUBSCRIPTION done."

逻辑复制停止脚本

#!/bin/sh
# 本机密码
PASSWORD=PG_PWD
# 查询iuser用户下的所有数据库
database_name_result=$(PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "
SELECT d.datname AS database_name FROM pg_database d JOIN pg_user u ON d.datdba = u.usesysid WHERE u.usename = 'iuser';")
# 检查查询结果是否为空
if [ -z "$database_name_result" ]; then# 查询结果为空exit 1
fi
# 遍历每个数据库
while IFS= read -r database_name; dodatabase_name=$(echo "$database_name" | sed 's/ //g')echo "DROP PUBLICATION&SUBSCRIPTION"# 删除之前可能存在的发布、订阅关系PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "DROP PUBLICATION IF EXISTS pub_$database_name;"PGPASSWORD=$PASSWORD psql -h 127.0.0.1 -p 5432 -U iuser -t -c "DROP SUBSCRIPTION IF EXISTS sub_$database_name;"echo "DROP $database_name PUBLICATION&SUBSCRIPTION done."
done <<< "$database_name_result"
echo "PUBLICATION done."

延迟测试

100w测试

delete from users;
insert into users select generate_series(1,1000000), 'anna', 18;
delete from users;
> Affected rows: 1000000
> 时间: 2.024s

删除100w行需要时间2s,观测延迟

select * from users limit 1;  
\watch 1  开始时间
2022年02月18日 星期五 18时18分03秒 (每 1s)id | name | age 
----+------+-----1  | anna |  18
(1 行记录)
结束时间  
2022年02月18日 星期五 18时18分25秒 (每 1s)id | name | age 
----+------+-----
(0 行记录)

延迟20s左右

10w测试

insert into users select generate_series(1,100000), 'anna', 18;
delete from users;
> Affected rows: 100000
> 时间: 0.229s

删除10w行需要时间0.2s,观测延迟

select * from users limit 1;  
\watch 1  开始时间
2022年02月18日 星期五 18时29分20秒 (每 1s)id | name | age 
----+------+-----1  | anna |  18
(1 行记录)结束时间  2022年02月18日 星期五 18时29分22秒 (每 1s)id | name | age 
----+------+-----
(0 行记录)

延迟2s左右,取决于一次性事务大小。

相关问题

逻辑复制配置双向复制WAL循环

-- 正向发布
CREATE TABLE t(a SERIAL, b CHAR);
create publication testpub1 FOR table t; 
-- 正向订阅
CREATE TABLE t(a SERIAL, b CHAR);
create subscription testsub1 connection 'host=172.168.98.107 port=5432 dbname=testdb user=replication' publication testpub1;
-- 反向发布
create publication testpub2 FOR table t; 
-- 反正订阅
create subscription testsub2 connection 'host=172.168.98.115 port=5432 dbname=testdb user=replication' publication testpub2;

至此已经创建了一个双向循环复制,如图所示。

在这里插入图片描述

此时我在发布端插入一条数据就会出现环绕现像。此时就会出现循环。不停的从A复制到B,再从B复制到A,直到把数据库搞崩。双向复制需要使用不同的表来实现。使用同样的表会产生WAL循环。

相关链接

1. PostgreSQL10官网文档
https://www.postgresql.org/docs/10/index.html
2. PostgreSQL10逻辑特性
https://www.postgresql.org/docs/10/logical-replication.html
3. 逻辑解码
https://docs.microsoft.com/zh-cn/azure/postgresql/concepts-logical

总结

逻辑复制是PostgreSQL10引入的重要特性,为数据库提供了更灵活的同步方式。在高可用架构中,逻辑复制可用于数据同步、灾备切换、实时分析等场景,提升数据库的可扩展性和业务连续性。合理规划依然可以打造稳定高效的高可用架构。💡 想让你的数据库更可靠?逻辑复制值得一试!🚀

相关文章:

PostgreSQL10 逻辑复制实战:构建高可用数据同步架构!

PostgreSQL10 逻辑复制实战&#xff1a;打造高可用数据同步架构&#xff01; 概述 PostgreSQL 10 引入了逻辑复制&#xff08;Logical Replication&#xff09;&#xff0c;为数据库高可用和数据同步提供了更灵活的选择。PostgreSQL 复制机制主要分为物理复制和逻辑复制两种&…...

springboot之HTML与图片生成

背景 后台需要根据字段动态生成HTML&#xff0c;并生成图片&#xff0c;发送邮件到给定邮箱 依赖 <!-- freemarker模板引擎--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifa…...

455. 分发饼干(LeetCode)

题目来源&#xff1a; 455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09; 题目内容&#xff1a; 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xf…...

go设计模式

刘&#xff1a;https://www.bilibili.com/video/BV1kG411g7h4 https://www.bilibili.com/video/BV1jyreYKE8z 1. 单例模式 2. 简单工厂模式 代码逻辑&#xff1a; 原始&#xff1a;业务逻辑层 —> 基础类模块工厂&#xff1a;业务逻辑层 —> 工厂模块 —> 基础类模块…...

基于STM32的智能家居能源管理系统

1. 引言 传统家庭能源管理存在能耗监控粗放、设备联动不足等问题&#xff0c;难以适应绿色低碳发展需求。本文设计了一款基于STM32的智能家居能源管理系统&#xff0c;通过多源能耗监测、负荷预测与优化调度技术&#xff0c;实现家庭能源的精细化管理与智能优化&#xff0c;提…...

win11编译pytorchaudio cuda128版本流程

1. 前置条件 本篇续接自 win11编译pytorch cuda128版本流程&#xff0c;阅读前请先参考上一篇配置环境。 访问https://kkgithub.com/pytorch/audio/archive/refs/tags/v2.6.0.tar.gz下载源码&#xff0c;下载后解压&#xff1b; 2. 编译 在visual studio 2022安装目录下查找…...

Rust学习总结之-match

Rust 有一个叫做 match 的极为强大的控制流运算符&#xff0c;它允许我们将一个值与一系列的模式相比较&#xff0c;并根据相匹配的模式执行相应代码。模式可由字面量、变量、通配符和许多其他内容构成。 一&#xff1a;match定义 可以把 match 表达式想象成某种硬币分类器&a…...

基于Three.js的3D赛车游戏开发实战详解

目录 一、项目效果预览二、核心技术架构2.1 三维场景构建2.2 赛道与车辆模型2.3 光照系统三、核心运动系统3.1 车辆运动控制3.2 物理模拟公式3.3 边界限制四、摄像机控制系统4.1 第三人称视角数学原理4.2 鼠标交互实现五、星空背景特效5.1 点云生成算法5.2 动态闪烁效果六、性能…...

51单片机中reg52.h与regx52.h在进行位操作时的不同

reg52.h中不能使用例如 P2_0;这样的定义 而只能使用 P2^0;这样的定义 但是都不可以对位进行直接赋值操作&#xff1b; 而 regx52.h中可以使用 P2_0和P2^0&#xff1b;但是只有使用下划线的才可以对位进行赋值操作 例如P2_0 1; 但不可以是P2^0 1; 在 C 语言中&#xff0c;…...

Git GitHub基础

git是什么&#xff1f; Git是一个分布式版本控制系统&#xff0c;用于管理源代码的变更。它允许多个开发者在同一个项目上协作&#xff0c;同时跟踪每个修改的历史记录。 关键词&#xff1a; 分布式版本控制软件 软件 安装到我们电脑上的一个工具 版本控制 例如论文&…...

【Excel】 Power Query抓取多页数据导入到Excel

抓取多页数据想必大多数人都会&#xff0c;只要会点编程技项的人都不会是难事儿。那么&#xff0c;如果只是单纯的利用Excel软件&#xff0c;我还真的没弄过。昨天&#xff0c;我就因为这个在网上找了好久发好久。 1、在数据-》新建查询-》从其他源-》自网站 &#xff0c;如图 …...

视频批量分段工具

参考原文&#xff1a;视频批量分段工具 选择视频文件 当您启动这款视频批量分段工具程序后&#xff0c;有两种便捷的方式来选择要处理的视频文件。其一&#xff0c;您可以点击程序界面中的 “文件” 菜单&#xff0c;在下拉选项里找到 “选择视频文件” 按钮并点击&#xff1b…...

Redis 源码分析-内部数据结构 robj

Redis 源码分析-内部数据结构 robj Redis 中&#xff0c;一个 database 内的这个映射关系是用一个 dict 来维护的&#xff08;ht[0]&#xff09;。dict 的 key 固定用一种数据结构来表达就够了&#xff0c;即动态字符串 sds。而 value 则比较复杂&#xff0c;为了在同一个 dic…...

多通道数据采集和信号生成的模块化仪器如何重构飞机电子可靠性测试体系?

飞机的核心电子系统包括发电与配电系统&#xff0c;飞机内部所有设备和系统之间的内部数据通信系统&#xff0c;以及用于外部通信的射频设备。其他所有航空电子元件都依赖这些关键总线进行电力传输或数据通信。在本文中&#xff0c;我们将了解模块化仪器&#xff08;无论是PCIe…...

面试(进阶) —虚拟列表在什么场景使用,如何实现?

面试(进阶) —虚拟列表在什么场景使用&#xff0c;如何实现&#xff1f; 在前端开发中&#xff0c;当需要渲染大量数据时&#xff0c;传统的渲染方式往往会遇到性能瓶颈。一次性将大量数据渲染到DOM中&#xff0c;不仅会导致页面加载缓慢&#xff0c;还可能占用大量内存&#x…...

Python—Excel全字段转json文件(极速版+GUI界面打包)

目录 专栏导读1、背景介绍2、库的安装3、核心代码4、完整代码(简易版)5、进阶版(GUI)总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 该系列文章专栏:请点击——…...

【Linux第一弹】Linux基础指令(上)

目录 1.ls指令 1.1 ls使用实例 2.pwd指令 3.cd指令 3.1 cd使用实例 4.touch指令 4.1touch使用实例 5.mkdir指令 5.1mkdir使用实例 6.rmdir指令和rm指令 6.1 rmdir指令使用实例->: 6.2 rm指令使用实例 7.man指令 8.cp指令 8.1 cp 使用实例 9.mv指令 9.1mv使用…...

DeepSeek教unity------UI元素长按响应

主要功能说明&#xff1a; ​长按检测&#xff1a;通过记录指针按下的时间&#xff0c;判断是否达到 longClickTime&#xff0c;从而触发长按事件。​状态管理&#xff1a;使用 StateEnum 枚举管理点击项的当前状态&#xff08;未按下、按下等待长按、长按已触发&#xff09;。…...

Netty为什么性能很高?

大家好&#xff0c;我是锋哥。今天分享关于【Netty为什么性能很高?】面试题。希望对大家有帮助&#xff1b; Netty为什么性能很高? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Netty是一款高性能的网络通信框架&#xff0c;主要用于构建高性能的网络应用程序。…...

[深度学习] 大模型学习2-提示词工程指北

在文章大语言模型基础知识里&#xff0c;提示词工程&#xff08;Prompt Engineering&#xff09;作为大语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;应用构建的一种方式被简要提及&#xff0c;本文将着重对该技术进行介绍。 提示词工程就是在和LLM聊…...

MySQL 和 PostgreSQL 的详细对比

以下是 MySQL 和 PostgreSQL 的详细对比&#xff0c;帮助您根据需求选择合适的数据库&#xff1a; 1. 核心特性对比 特性MySQLPostgreSQL数据库类型关系型数据库 (RDBMS)关系型数据库 (RDBMS)&#xff0c;支持部分 NoSQL 特性SQL 标准兼容性部分兼容&#xff08;简化语法&…...

基于POI的Excel下拉框自动搜索,包括数据验证的单列删除

目录 目标 例子 1.搜索下拉框页 2.数据源页 3.效果 代码以及注意事项 1.代码 2.注意事项 1.基于Excel的话&#xff0c;相当于加入了一个【数据验证】 2.代码中的一些方法说明 目标 期望在Excel利用代码创建具备自动搜索功能的下拉框 例子 1.搜索下拉框页 2.数据源…...

Android中使用Robolectric测试点击事件(不需要手机)

文章目录 一、前言二、简单示例三、参考文档 一、前言 Robolectric 是一个由 Google 维护的开源 Android 测试框架&#xff0c;它允许你以 Android 运行时环境运行单元测试。 Robolectric 提供了一个模拟 Android 运行时环境&#xff0c;允许你测试你的代码是否正确地使用 And…...

C++Primer学习(4.7 条件运算符)

4.7 条件运算符 条件运算符( ? :)允许我们把简单的if-else逻辑嵌入到单个表达式当中&#xff0c;条件运算符按照如下形式使用: cond ? exprl : expr2; 其中cond是判断条件的表达式&#xff0c;而expr1和expr2是两个类型相同或可能转换为某个公共类型的表达式。条件运算符的执…...

Python 数据可视化(一)熟悉Matplotlib

目录 一、安装包 二、先画个折线图 1、修改标签文字和线条粗细 2、内置样式 3、scatter() 绘制散点图 4、scatter() 绘制多个点 5、设置样式 6、保存绘图 数据可视化指的是通过可视化表示来探索和呈现数据集内的规律。 一、安装包 win R 打开终端 安装 Matplotlib&…...

c#实现485协议

在C#中实现RS-485协议通信,需要结合串口(SerialPort)操作和硬件收发控制(如RTS信号切换)。以下是详细的步骤和示例代码: 1. RS-485通信原理 物理层:RS-485是差分信号标准,支持多点通信(半双工)。 收发控制:通过控制RTS(Request to Send)或DTR引脚切换发送/接收模式…...

考研出分24小时,人类精神状态图鉴

2月24日&#xff0c;上午10点起&#xff0c;各省考研初试成绩陆续公布&#xff0c;考生们或紧张的输入准考证号&#xff0c;或抱团等待“审判”。然而更魔幻的还在后头——下午4点&#xff0c;教育部竟在同一天直接发布了《2025年研考国家分数线》。 不少网友表示&#xff1a;…...

神经网络AI原理回顾

长期记忆存储在大模型的参数权重中&#xff0c;不经过推理和编码无法读取&#xff0c;且必须依赖输入的提示&#xff0c;因为大模型不会无缘无故的自言自语&#xff0c;毕竟输入层是它唯一 与外界交互的窗口。 目前个性化大模型的局限就是训练成本过高&#xff0c;除非使用RAG&…...

不同数据类型在数据库和编程语言之间的对应关系表

不同数据类型在数据库和编程语言之间的对应关系表 MySql 与 C# MySqlC#varcharstringbigintlongbigint unsignedulongintintint unsigneduintsmallintshortsmallint unsignedushortVARCHAR(36)GuidsmalldatetimeDateTimedateDateTimedatetimeDateTimetimestampDateTimefloatf…...

数据库导出

MySQL数据库 使用命令行导出 导出整个数据库&#xff1a;在命令行中输入mysqldump -u用户名 -p密码 数据库名 > 导出文件路径/文件名.sql。例如mysqldump -uroot -p123456 mydb > /home/user/mydb_backup.sql&#xff0c;回车后输入密码即可将名为mydb的数据库导出为SQL…...