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

如何使用SQL系列 之 如何在MySQL中使用存储过程

引言

通常,当使用关系型数据库时,你直接在应用程序代码中发出单独的结构化查询语言(SQL)查询来检索或操作数据,如SELECTINSERTUPDATEDELETE。这些语句直接作用于并操作底层数据库表。如果相同的语句或一组语句中使用多个应用程序访问同一个数据库,他们经常重复的在单独的应用程序。

与许多其他关系型数据库管理系统类似,MySQL支持使用存储过程。存储过程帮助组织一个或多个SQL语句重用在一个共同的名字,将常见的业务逻辑封装在数据库本身。这样的过程可以从访问数据库的应用程序中调用,以一致的方式检索或操作数据。

使用存储过程,您可以创建可重用的例程常见任务跨多个应用程序使用,提供数据验证,或者提供一个额外的数据访问层安全通过限制数据库用户直接访问底层表和发行任意查询。

在本教程中,您将了解哪些存储过程以及如何创建基本的存储过程,返回数据,并使用输入和输出参数。

前期准备

遵循这个指南,你将需要一个计算机运行一个基于sql的关系数据库管理系统(RDBMS)。本指南中的说明和示例使用以下环境进行了验证:

  • 基本熟悉执行SELECT查询以从数据库中检索数据,如如何从SQL指南中的表中选择行所述。

注意:许多RDBMS使用它们自己的SQL实现。虽然触发提到作为一个SQL标准的一部分,标准不严格执行他们的语法或实现它们的方法。因此,它们的实现在不同的数据库中是不同的。本教程中概述的命令使用MySQL数据库的语法,可能无法在其他数据库引擎上工作。

你还需要一个数据库,其中一些表加载了示例数据,这样你就可以练习使用函数。我们鼓励您通过以下连接到示例数据库MySQL和建立一个连接到MySQL服务器上部分细节,创建测试数据库在本指南中使用的例子。

连接到MySQL并设置一个示例数据库

如果SQL数据库系统运行在远程服务器上,请从本地设备SSH到服务器:

ssh sammy@your_server_ip

然后打开MySQL服务器提示符,将sammy替换为你的MySQL用户账户的名称:

mysql -u sammy -p

创建一个名为procedures的数据库:

CREATE DATABASE procedures;

如果数据库成功创建,您将收到这样的输出:

OutputQuery OK, 1 row affected (0.01 sec)

要选择procedures数据库,运行以下USE语句:

USE procedures;
OutputDatabase changed

选择数据库后,您可以在其中创建示例表。cars表将包含数据库中关于汽车的简化数据。它将保存以下列:

  • make:这一列保存了每辆汽车的make值,使用最多100个字符的varchar数据类型表示。
  • model:这一列保存了汽车模型名称,使用varchar数据类型表示,最多不超过100个字符。
  • year:这一列存储汽车的制造年份,使用int数据类型来保存数值。
  • value:该列使用decimal数据类型存储汽车的值,最多为10位,小数点后为2位。

使用下面的命令创建示例表:

CREATE TABLE cars (make varchar(100),model varchar(100),year int,value decimal(10, 2)
);

如果输出结果如下所示,说明表已经创建:

OutputQuery OK, 0 rows affected (0.00 sec)

接下来,通过运行以下INSERT INTO操作来加载包含一些示例数据的cars表:

INSERT INTO cars
VALUES
('Porsche', '911 GT3', 2020, 169700),
('Porsche', 'Cayman GT4', 2018, 118000),
('Porsche', 'Panamera', 2022, 113200),
('Porsche', 'Macan', 2019, 27400),
('Porsche', '718 Boxster', 2017, 48880),
('Ferrari', '488 GTB', 2015, 254750),
('Ferrari', 'F8 Tributo', 2019, 375000),
('Ferrari', 'SF90 Stradale', 2020, 627000),
('Ferrari', '812 Superfast', 2017, 335300),
('Ferrari', 'GTC4Lusso', 2016, 268000);

INSERTINTO操作将向表格中添加10辆跑车样本,其中包括5辆保时捷和5辆法拉利。下面的输出表明已经添加了5行数据:

OutputQuery OK, 10 rows affected (0.00 sec)
Records: 10  Duplicates: 0  Warnings: 0

有了这些我们就可以按照本指南的其余部分开始使用SQL中的存储过程了。

存储过程简介

在MySQL和许多其他关系数据库系统中,存储过程是命名对象,其中包含一条或多条指令,调用后由数据库按顺序执行。在最基本的例子中,一个存储过程可以节省一个共同声明在一个可重用的程序,如与常用过滤器从数据库中检索数据。例如,可以创建一个存储过程来检索在最近给定的几个月内下过订单的在线商店客户。在最复杂的场景中,存储过程可以表示为健壮应用程序描述复杂业务逻辑的广泛程序。

存储过程中的指令集可以包括常见的SQL语句,如SELECTINSERT查询,用于返回或操作数据。此外,存储过程可以利用:

  • 传递给存储过程或通过存储过程返回的参数;
  • 在程序代码中声明变量,直接处理检索到的数据;
  • 条件语句,允许根据特定条件执行部分存储过程代码,例如IFCASE指令;
  • 循环,例如WHILELOOPREPEAT,允许多次执行代码的某些部分,例如检索数据集中的每一行;
  • 错误处理指令,例如向访问过程的数据库用户返回错误消息;
  • 对数据库中其他存储过程的调用;

注意:MySQL支持的广泛语法允许使用存储过程编写健壮的程序和解决复杂的问题。本指南只介绍存储过程的基本用法,存储过程体中包含SQL语句、输入和输出参数。执行条件代码、使用变量、循环和自定义错误处理超出了本指南的范围。你可以在MySQL官方文档中了解更多关于存储过程的信息。

当过程按其名称调用时,数据库引擎按定义的一条指令一条指令地执行它。

数据库用户必须具有执行给定过程的适当权限。这个权限要求提供了一个安全层,不允许直接访问数据库,同时允许用户访问保证可以安全执行的各个过程。

存储过程直接在数据库服务器上执行,在本地执行所有计算,并仅在完成时将结果返回给调用用户。

如果要更改过程行为,可以更新数据库中的过程,使用该过程的应用程序将自动选择新版本。所有用户将立即开始使用新的程序代码,而无需调整他们的应用程序。

下面是用于创建存储过程的SQL代码的一般结构:

DELIMITER //
CREATE PROCEDURE procedure_name(parameter_1, parameter_2, . . ., parameter_n)
BEGINinstruction_1;instruction_2;. . .instruction_n;
END //
DELIMITER ;

这段代码片段中的第一个和最后一个指令是DELIMITER //DELIMITER;。通常,MySQL使用分号(‘;’)来分隔语句,表示语句的开始和结束。如果在MySQL控制台中执行多个语句,语句之间用分号分隔,它们将被视为单独的命令,并一个接一个地独立执行。但是,存储过程可以包含多个命令,这些命令在被调用时将顺序执行。这给MySQL创建新过程带来了困难。数据库引擎会在存储过程体中遇到分号,并认为应该停止执行该语句。在这种情况下,预期的语句是整个过程创建代码,而不是过程本身中的一条指令,因此MySQL会误解您的意图。

要解决这个限制,可以使用DELIMITER命令在CREATE PROCEDURE调用期间临时将分隔符从;更改为//。然后,存储过程体中的所有分号将按原样传递给服务器。整个过程完成后,分隔符更改回带有最后一个 delimiter;;

创建新过程的核心代码是create procedure调用,后面跟着过程的名称:在示例中是procedure_name。过程名称后面是过程接受的可选参数列表。最后一部分是过程体,包含在BEGINEND语句中。其中是过程代码,可以包含单个SQL语句,如SELECT查询或更复杂的代码。

END命令以临时分隔符//结尾,而不是典型的分号。

在下一节中,您将创建一个包含单个查询的没有参数的基本存储过程。

创建不带参数的存储过程

在本节中,你将创建你的第一个存储过程,它封装了一条SQL SELECT语句,以返回按品牌和价值降序排列的拥有汽车列表。

首先执行你将要使用的SELECT语句:

SELECT * FROM cars ORDER BY make, value DESC;

汽车的数据库将返回列表的cars表,第一个命令,然后在单一,降序排列的价值:

Output+---------+---------------+------+-----------+
| make    | model         | year | value     |
+---------+---------------+------+-----------+
| Ferrari | SF90 Stradale | 2020 | 627000.00 |
| Ferrari | F8 Tributo    | 2019 | 375000.00 |
| Ferrari | 812 Superfast | 2017 | 335300.00 |
| Ferrari | GTC4Lusso     | 2016 | 268000.00 |
| Ferrari | 488 GTB       | 2015 | 254750.00 |
| Porsche | 911 GT3       | 2020 | 169700.00 |
| Porsche | Cayman GT4    | 2018 | 118000.00 |
| Porsche | Panamera      | 2022 | 113200.00 |
| Porsche | 718 Boxster   | 2017 |  48880.00 |
| Porsche | Macan         | 2019 |  27400.00 |
+---------+---------------+------+-----------+
10 rows in set (0.00 sec)

最有价值的法拉利在榜单的顶端,最不值钱的保时捷在榜单的底部。

假设此查询将在多个应用程序或多个用户中频繁使用,并希望确保每个人都使用完全相同的结果排序方式。为此,需要创建一个存储过程,将该语句保存在可重用的命名过程中。

要创建这个存储过程,执行以下代码片段:

DELIMITER //
CREATE PROCEDURE get_all_cars()
BEGINSELECT * FROM cars ORDER BY make, value DESC;
END //
DELIMITER ;

如上一节所述,第一个和最后一个命令(DELIMITER //DELIMITER;)告诉MySQL在创建过程期间停止将分号作为语句分隔符。

CREATE PROCEDURE SQL命令后面跟着过程名称get_all_cars,您可以定义该名称以最好地描述过程的功能。在过程名之后,有一对括号(),您可以在其中添加参数。在这个例子中,过程不使用参数,因此括号为空。然后,在定义过程代码块开始和结束的BEGINEND命令之间,之前使用的SELECT语句会一字不差地编写。
注意:取决于你的MySQL用户权限,在执行CREATE PROCEDURE命令时,你可能会收到一个错误:ERROR 1044 (42000): Access denied for user 'sammy'@'localhost' to database 'procedures'。要授予用户创建和执行存储过程的权限,请以root身份登录MySQL并执行以下命令,根据需要替换MySQL用户名和主机:

GRANT CREATE ROUTINE, ALTER ROUTINE, EXECUTE on *.* TO 'sammy'@'localhost';
FLUSH PRIVILEGES;

更新用户权限后,以root身份注销,以该用户身份重新登录,并重新运行CREATE PROCEDURE语句。

您可以在Stored Routines and MySQL Privileges文档中了解有关为数据库用户应用存储过程权限的更多信息。

数据库会响应一个成功的信息:

OutputQuery OK, 0 rows affected (0.02 sec)

get_all_cars过程现在保存在数据库中,当被调用时,它将按原样执行保存的语句。
要执行保存的存储过程,可以使用CALL SQL命令后跟过程名称。试着像这样运行新创建的过程:

CALL get_all_cars;

使用该过程只需使用过程名get_all_cars即可。你不再需要手动输入之前使用的SELECT语句的任何部分。数据库将显示结果,就像之前运行SELECT语句一样:

Output+---------+---------------+------+-----------+
| make    | model         | year | value     |
+---------+---------------+------+-----------+
| Ferrari | SF90 Stradale | 2020 | 627000.00 |
| Ferrari | F8 Tributo    | 2019 | 375000.00 |
| Ferrari | 812 Superfast | 2017 | 335300.00 |
| Ferrari | GTC4Lusso     | 2016 | 268000.00 |
| Ferrari | 488 GTB       | 2015 | 254750.00 |
| Porsche | 911 GT3       | 2020 | 169700.00 |
| Porsche | Cayman GT4    | 2018 | 118000.00 |
| Porsche | Panamera      | 2022 | 113200.00 |
| Porsche | 718 Boxster   | 2017 |  48880.00 |
| Porsche | Macan         | 2019 |  27400.00 |
+---------+---------------+------+-----------+
10 rows in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)

您现在已经成功地创建了一个没有任何参数的存储过程,它以特定的方式从cars表中排序返回所有汽车。您可以跨多个应用程序使用该过程。

在下一节中,您将创建一个过程,它接受参数,根据用户输入更改过程行为。

创建带参数的存储过程

在本节中,您将包括存储过程定义的输入参数,以允许执行该过程的用户向其传递数据。例如,用户可以提供查询过滤器。

之前创建的存储过程get_all_cars始终从cars表中检索所有汽车。让我们创建另一个程序找到汽车从一个给定的制造业。为此,需要在过程定义中定义一个命名参数。

运行下面的代码:

DELIMITER //
CREATE PROCEDURE get_cars_by_year(IN year_filter int
)
BEGINSELECT * FROM cars WHERE year = year_filter ORDER BY make, value DESC;
END //
DELIMITER ;

对上一节中的过程创建代码有几个更改。

首先,这个方法的名字是get_cars_by_year,它描述了这个过程:根据生产年份检索汽车。

之前为空的括号现在包含了一个参数定义:IN year_filter intIN关键字告诉数据库,该参数将由调用用户传递* *过程。year_filter是参数的任意名称。您将使用它来引用过程代码中的参数。最后,int是数据类型。在这种情况下,生产表示为一个数值。

在过程名称之后定义的year_filter参数出现在WHERE year =year_filter 子句中的SELECT语句中,根据生产年份过滤cars表。

数据库将再次返回成功消息:

OutputQuery OK, 0 rows affected (0.02 sec)

试试不传递任何参数就执行这个过程,就像你之前做的那样:

CALL get_cars_by_year;

MySQL数据库将返回一条错误消息:

Error messageERROR 1318 (42000): Incorrect number of arguments for PROCEDURE procedures.get_cars_by_year; expected 1, got 0

这一次,提供存储过程预计参数,但没有。要调用带有参数的存储过程,可以按照过程所期望的顺序在括号内提供参数值。要检索在2017中生产的汽车,执行:

CALL get_cars_by_year(2017);

现在,被调用的过程将正确执行,并返回当年的汽车列表:

Output+---------+---------------+------+-----------+
| make    | model         | year | value     |
+---------+---------------+------+-----------+
| Ferrari | 812 Superfast | 2017 | 335300.00 |
| Porsche | 718 Boxster   | 2017 |  48880.00 |
+---------+---------------+------+-----------+
2 rows in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)

在本例中,您了解了如何将输入参数传递给存储过程,并在过程中的查询中使用它们来提供筛选选项。

在下一节中,您将使用输出参数创建程序返回多个不同的值在一个单一的运行。

创建带有输入和输出参数的存储过程

在前面的两个例子中,你创建的存储过程都调用了SELECT语句来获取结果集。但是在某些情况下,您可能需要一个存储过程返回多个不同的值,而不是一个为一个单独的查询结果集。

假设您想创建一个过程,它将提供给定年份的汽车的汇总信息,包括收集中的汽车数量和它们的市场价值(最小值、最大值和平均值)。

为此,您可以在创建新存储过程时使用OUT参数。与IN参数类似,OUT参数也有与其关联的名称和数据类型。但是,除了向存储过程传递数据之外,存储过程还可以向它们填充数据,以便向调用用户返回值。

创建一个get_car_stats_by_year过程,使用输出参数返回给定生产年份的汽车汇总数据:

DELIMITER //
CREATE PROCEDURE get_car_stats_by_year(IN year_filter int,OUT cars_number int,OUT min_value decimal(10, 2),OUT avg_value decimal(10, 2),OUT max_value decimal(10, 2)
)
BEGINSELECT COUNT(*), MIN(value), AVG(value), MAX(value)INTO cars_number, min_value, avg_value, max_valueFROM carsWHERE year = year_filter ORDER BY make, value DESC;
END //
DELIMITER ;

这一次,除了用于按生产年份过滤汽车的IN参数year_filter外,括号块中还定义了四个OUT参数。cars_number参数是用int表示数据类型和将用于返回集合中的汽车的数量。min_valueavg_valuemax_value参数表示市场值,并用decimal(10,2)类型定义(类似于cars表中的value列)。这些将用于返回集合中最便宜和最昂贵的汽车的信息,以及所有匹配汽车的平均价格。

SELECT语句使用SQL的数学函数从cars表中查询了四个值:COUNT来获得汽车的总数,MINAVGMAXvalue列中获得最小值、平均值和最大值。

注意:要了解更多关于在SQL中使用数学函数的信息,你可以参考SQL教程中如何使用数学表达式和聚集函数。

为了告诉数据库该查询的结果应该存储在存储过程的输出参数中,引入了一个新的关键字INTO。在INTO关键字之后,列出了与检索到的数据相对应的四个过程参数的名称。这样,MySQL将COUNT(*)的值保存到cars_number参数中,MIN(value)的结果保存到min_value参数中,以此类推。

数据库将确认过程创建成功:

OutputQuery OK, 0 rows affected (0.02 sec)

现在通过执行以下命令来运行这个新过程:

CALL get_car_stats_by_year(2017, @number, @min, @avg, @max);

这四个新参数以“@”符号开始。它们是MySQL控制台中的局部变量名,可以用来临时存储数据。当您将这些变量传递给刚刚创建的存储过程时,存储过程将向这些变量插入值。

数据库将响应:

OutputQuery OK, 1 row affected (0.00 sec)

这与之前的行为不同,之前的行为是立即在屏幕上显示结果。这是因为存储过程的结果保存在输出参数中,而不是作为查询结果返回。要访问结果,你可以直接在MySQL shell中SELECT它们,如下所示:

SELECT @number, @min, @avg, @max;

使用此查询,您将从局部变量中选择值,而不是再次调用该过程。存储过程将结果保存在这些变量中,直到断开与shell的连接,这些数据才会恢复。

注意:要了解更多关于在MySQL中使用用户定义变量的信息,请参阅文档中的用户定义变量部分。在应用程序开发中,访问存储过程返回的数据的方法在不同的编程语言和框架中是不同的。有疑问时,请您选择的语言和框架的文档。

输出将显示查询变量的值:

Output+---------+----------+-----------+-----------+
| @number | @min     | @avg      | @max      |
+---------+----------+-----------+-----------+
|       2 | 48880.00 | 192090.00 | 335300.00 |
+---------+----------+-----------+-----------+
1 row in set (0.00 sec)

这些值对应于“2017年”生产的汽车数量,以及从这一年生产的汽车的最低、平均和最高市场价值。

在这个示例中,您学习了如何使用输出参数从存储过程中返回多个不同的值以供以后使用。在下一节中,我们将学习如何删除创建的过程。

删除存储过程

在本节中,我们将删除数据库中的存储过程。

有时您创建的过程可能不再需要。在其他情况下,您可能想要改变这个过程的工作方式。MySQL不允许在创建过程后更改过程定义,因此唯一的方法是先删除过程,然后按照所需的更改重新创建它。

让我们删除最后一个过程,get_car_stats_by_year。为此,你可以使用DROP PROCEDURE语句:

DROP PROCEDURE get_car_stats_by_year;

数据库将以成功消息确认过程删除成功:

OutputQuery OK, 0 rows affected (0.02 sec)

您可以通过尝试调用过程来验证该过程是否已被删除。执行:

CALL get_car_stats_by_year(2017, @number, @min, @avg, @max);

这一次,你会看到一条错误消息,说这个过程在数据库中不存在:

Error messageERROR 1305 (42000): PROCEDURE procedures.get_car_stats_by_year does not exist

在本部分中,您已经了解了如何删除现有数据库中的存储过程。

总结

通过本指南,您了解了什么是存储过程,以及如何在MySQL中使用存储过程将可重用语句保存到命名过程中,然后再执行它们。您创建了不带参数的存储过程,以及使用输入和输出参数使其更加灵活的过程。

您可以使用存储过程来创建可重用的例程和跨多个应用程序访问数据的统一方法,以及实现超出单个SQL查询所提供的可能性的复杂行为。本教程只介绍了使用存储过程的基础知识。要了解更多信息,请参阅MySQL存储过程文档。

相关文章:

如何使用SQL系列 之 如何在MySQL中使用存储过程

引言 通常,当使用关系型数据库时,你直接在应用程序代码中发出单独的结构化查询语言(SQL)查询来检索或操作数据,如SELECT、INSERT、UPDATE或DELETE。这些语句直接作用于并操作底层数据库表。如果相同的语句或一组语句中使用多个应用程序访问同…...

用 Github Codespaces 免费搭建本地开发测试环境

如何丝滑地白嫖一个本地开发环境?怎么新建一个代码空间? 1:通过Github网页新建2:通过VSCode插件新建 为代码创建相应的开发测试环境 如何丝滑地白嫖一个本地开发环境? 使用Codespaces为开发者解决这样的痛点&#xf…...

PyTorch实战-实现神经网络图像分类基础Tensor最全操作详解(一)

目录 前言 一、PyTorch数据结构-Tensor 1.什么是Tensor 2.数据Tensor使用场景 3.张量形态 标量(0D 张量) 向量(1D 张量) 矩阵(2D张量) 3D 张量与高维张量 二、Tensor的创建 1. 从列表或NumPy数组创建 2. 使用特定的初始…...

第29章_瑞萨MCU零基础入门系列教程之改进型环形缓冲区

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id728461040949 配套资料获取:https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总: ht…...

如何搭建一个react项目(详细介绍)

要搭建一个基本的 React 项目,你需要执行以下步骤。在开始之前,请确保你已经安装了 Node.js 和 npm(Node 包管理器)。 搭建一个React项目 1,创建项目目录2,初始化项目3,安装 React 和 ReactDOM4…...

ActiveMQ用法

ActiveMQ 和 JMS的关系? ActiveMQ是流行的开源消息中间件,JMS是Java平台定义的一种消息传递的标准。ActiveMQ实现了JMS规范,因此可以使用JMS API来与ActiveMQ进行交互。 JMS定义了一种标准的API。API包括了一些接口和类,用于创建…...

TouchGFX之缓存位图

位图缓存是专用RAM缓冲区,应用可将位图保存(或缓存)在其中。 如果缓存了位图,在绘制位图时,TouchGFX将自动使用RAM缓存作为像素来源。位图缓存在许多情况下十分有用。 从RAM读取数据通常比从闪存读取要快(特…...

线性代数的本质(十)——矩阵分解

文章目录 矩阵分解LU分解QR分解特征值分解奇异值分解奇异值分解矩阵的基本子空间奇异值分解的性质矩阵的外积展开式 矩阵分解 矩阵的因式分解是把矩阵表示为多个矩阵的乘积,这种结构更便于理解和计算。 LU分解 设 A A A 是 m n m\times n mn 矩阵,…...

vue实现鼠标拖拽div左右移动的功能

直接代码&#xff1a; <template><div class"demo"><div class"third-part" id"发展历程"><div class"title">发展历程</div><div class"content" id"nav" v-if"dataList…...

基于Python和mysql开发的商城购物管理系统分为前后端(源码+数据库+程序配置说明书+程序使用说明书)

一、项目简介 本项目是一套基于Python和mysql开发的商城购物管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Python学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过…...

MySQL内外连接、索引特性

目录 内连接 外连接 索引特性 理解索引 删除索引 MySQL内外连接是一种用于联接两个或多个表的操作。内连接只返回满足连接条件的行&#xff0c;外连接返回满足条件和不满足条件的行。 内连接 SQL如下&#xff1a; SELECT ... FROM t1 INNER JOIN t2 ON 连接条件 [INNER …...

滚动条设置

不同浏览器滚动条样式及滚动定位 是否可以滚动 overflow&#xff1a;scroll overflow&#xff1a;autooverflow:scroll – 只有超出了盒子才会有滚动条 overflow:auto – 一直有滚动的盒子&#xff0c;只是超出了盒子才会出现滚动条滑块&#xff0c;可以滚动 谷歌浏览器滚动…...

【AI】机器学习——感知机

文章目录 4.1 感知机基本概念4.2 策略4.2.1 数据集的线性可分性4.2.2 学习策略目标损失函数的构造关于距离的解释 4.3 算法4.3.1 原始形式损失函数的梯度下降法 4.3.2 PLA例题4.3.3 算法收敛性 4.4 PLA对偶形式4.4.1 原始PLA分析4.4.2 PLA对偶形式4.4.3 优点 4.1 感知机基本概念…...

蓝牙遥控器在T2-U上的应用

文章目录 简介优势使用流程示例代码遥控器命令表遥控器代码实现开启遥控器配对功能运行 简介 Tuya beacon 协议是基于 BLE 广播通信技术&#xff0c;完善配对解绑、组包拆包、群组管理、加密解密、安全策略&#xff0c;形成的一种轻量、安全的可接入涂鸦云的蓝牙协议。 蓝牙 …...

数据驱动的数字营销与消费者运营

引言&#xff1a;基于海洋馆文旅企业在推广宣传中&#xff0c;如何通过指标体系量化分析广告收益对业务带来的收益价值的思考&#xff1f; 第一部分:前链路引流投放的策略与实战 1.1 动态广告的实现: 偶然与必然 动态广告是一种基于实时数据和用户行为的广告形式&#xff0c;它…...

Qt点亮I.MX6U开发板的一个LED

本篇开始将会介绍与开发版相关的Qt项目&#xff0c;首先从点亮一个LED开始。I.MX6U和STM32MP157的相关信息都会用到&#xff0c;但是后期还是将I.MX6U的学习作为重点。当然其他开发版的开发也可以参考本博文。 文章目录 1. Qt是如何操控开发板上的一个LED2. 出厂内核设备树中注…...

网络摄像头-流媒体服务器-视频流客户端

取电脑的视频流 当涉及交通事件检测算法和摄像头视频数据处理时&#xff0c;涉及的代码案例可能会非常复杂&#xff0c;因为这涉及到多个组件和技术。以下是一个简单的Python代码示例&#xff0c;演示如何使用OpenCV库捕获摄像头视频流并进行实时车辆检测&#xff0c;这是一个…...

Django05_反向解析

Django05_反向解析 5.1 反向解析概述 随着功能的不断扩展&#xff0c;路由层的 url 发生变化&#xff0c;就需要去更改对应的视图层和模板层的 url&#xff0c;非常麻烦&#xff0c;不便维护。这个时候我们可以通过反向解析&#xff0c;将 url解析成对应的 试图函数 通过 path…...

基于HTML、CSS和JavaScript制作一个中秋节倒计时网页

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 这个项目使用HTML、CSS和…...

富斯I6刷10通道固件

使用USB转串口模块刷写10通道固件 一、下载固件 1. 十通道英文固件 下载地址: https://github.com/benb0jangles/FlySky-i6-Mod-/tree/master 选择 FlySky-i6-Mod–master \ 10ch Mod i6 Updater \ 10ch_MOD_i6_Programmer_V1 路径下的文件,亲测可用。 2. 原版六通道中…...

vector的模拟实现 总结

vector的模拟实现 总结 vector.hTest.cpp vector.h 1、迭代器的实现 #pragma oncenamespace JPC {template<class T>class vector{public://对于存储空间是连续的结构而言&#xff0c;可以用原身指针来 模拟实现 迭代器。typedef T* iterator;typedef const T* const_i…...

k8s中的有状态,无状态,pv、pvc等

数据库是一个典型的有状态服务&#xff0c;他的部署和无状态服务是不一样的。 PostgresSQL----基于Kubernetes部署PostgresSQL-CSDN博客 一、创建SC、PV和PVC存储对象 二、部署PostgresSQL Volume Kubernetes 中文指南——云原生应用架构实战手册 有状态应用&#xff1a; …...

springboot+jxls复杂excel模板导出

JXLS 是基于 Jakarta POI API 的 Excel 报表生成工具&#xff0c;可以生成精美的 Excel 格式报表。它采用标签的方式&#xff0c;类似 JSP 标签&#xff0c;写一个 Excel 模板&#xff0c;然后生成报表&#xff0c;非常灵活&#xff0c;简单&#xff01; Java 有一些用于创建 …...

用selenium webdriver获取网站cookie后,实现免登录上网站

以csdn为例&#xff0c;代码分为两部分。 一、csdn_get_cookies.py为半手动登录网站后获取cookies 二、csdn_use_cookies.py为使用获取到的cookies免登录上网站 #获取登录cookiesfrom selenium import webdriver import jsoncsdn_driver webdriver.Chrome() url "htt…...

如何使用Java进行安全测试?

要使用Java进行安全测试&#xff0c;可以按照以下步骤进行&#xff1a; 确定测试目标&#xff1a;首先&#xff0c;明确要测试的应用程序或系统的安全目标和需求。确定要测试的安全方面&#xff0c;如身份验证、授权、输入验证、安全配置等。 了解安全测试知识&#xff1a;熟悉…...

Linux之Socket函数(详细篇)

本篇是基于Linux man手册的一些总结 socket作用&#xff1a; create an endpoint for communication 函数结构 c #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol); 描述 socket() …...

Dajngo06_Template模板

Dajngo06_Template模板 6.1 Template模板概述 模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术 静态网页&#xff1a;页面上的数据都是写死的&#xff0c;万年不变 动态网页&#xff1a;页面上的数据是从后端动态获取的&#xff08;后端获取数据库…...

快速幂 c++

一般大家写都是 int ans 1; for (int i 1; i < a; i )ans * x;时间复杂度 但是这对于我们还不够&#xff0c;我们要 首先我们得知道一个数学知识 那么求 就有以下递归式 a 能被2整除 a 不能被2整除 (这里a/2是整除) 所以每次都调用 不就是么 最后补充一个东西…...

分享一个基于微信小程序的医院口腔助手小程序 牙科诊所预约小程序 源码 lw 调试

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…...

Si3262 一款低功耗刷卡+触摸+mcu 三合一SOC芯片

Si3262是-款高度集成的低功耗soC芯片&#xff0c;其集成了基于RISC-V 核的低功耗MCU和工作在13.56MHz的非接触式读写器模块。 该芯片ACD模式下刷卡距离可达4-5cm&#xff08;天线决定&#xff09;&#xff0c;适用于智能门锁&#xff0c;电子锁&#xff0c;柜锁&#xff0c;桑拿…...

西安网站改版的公司/在线seo工具

left join on 和where条件的放置 对于left join&#xff0c;不管on后面跟什么条件&#xff0c;左表的数据全部查出来&#xff0c;因此要想过滤需把条件放到where后面 123select * from test2 left join test1 on test2.id test1.id where test2.id <>6 and test1.id<…...

iapp做网站/seo关键词排名优化联系方式

题目部分 原题链接 题目描述 传说很久以前&#xff0c;大地上居住着一种神秘的生物&#xff1a;地精。 地精喜欢住在连绵不绝的山脉中。具体地说&#xff0c;一座长度为N的山脉H可分为从左到右的N段&#xff0c;每段有一个独一无二的高度\(H\_i\)&#xff0c;其中\(H\_i\)是\(1…...

2013电子商务网站建设/清远新闻最新

前端网站中如果存在一些让用户填写内容的表单元素的话&#xff0c;我们可以使用JQ中获得焦点事件和失去焦点事件&#xff0c;来给用户作出一些提示的内容。今天我们就说一说JQuery下获得焦点和失去焦点的事件的使用方法。jquery focus()获得焦点事件focus()方法&#xff1a;当通…...

网站上可以做直播吗/网络推广与优化

这里阅读的php版本为PHP-7.1.0 RC3&#xff0c;阅读代码的平台为linux ZTS 我们会看到文章中有很多地方是: #ifdef ZTS # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) #else # define CG(v) (compiler_globals.v) extern ZEND_API struct _zend…...

网站空间是虚拟机吗/山东关键词网络推广

1、安装 yum install ghostscript 2、命令 gs -dSAFER -dBATCH -dNOPAUSE -r250 -dTextAlphaBits4 -dGraphicsAlphaBits4 -sDEVICEjpeg -sOutputFile2/%d.jpg 2.pdf 该命令是把2.pdf转换成jpg文件&#xff0c;放在2目录&#xff0c;前提是2目录已经存在&#xff0c;不存在会报错…...

滨州正规网站建设公司/软文发布平台

亲爱的读者朋友&#xff1a; 为了及时共享行业案例&#xff0c;通知共性问题&#xff0c;达成共享和提前预防&#xff0c;我们整理和编辑了《云和恩墨技术通讯》&#xff0c;通过对过去一段时间的知识回顾&#xff0c;故障归纳&#xff0c;以期提供有价值的信息供大家参考。同时…...