MySQL 存储函数[特殊字符] VS 存储过程[特殊字符]
1、存储函数😸
一、存储函数概述
存储函数是MySQL中一种特殊的存储程序,具有以下特点:
- 返回单个值:必须通过
RETURN
语句返回明确的结果 - SQL表达式使用:可以直接在
SQL语句中调用
- 输入参数:
只接受输入参数
(隐式IN),不支持OUT/INOUT参数 - 确定性🤔🤔🤔:可声明为
DETERMINISTIC
(相同输入总是返回相同结果)
二、存储函数语法结构
DELIMITER // -- 修改分隔符(可选)CREATE FUNCTION 函数名(参数1 数据类型,参数2 数据类型,...
)
RETURNS 返回值数据类型
[特性列表]
BEGIN-- 声明部分(DECLARE)-- 执行部分(SQL语句)-- 控制结构(IF/CASE/LOOP等)RETURN 返回值; -- 必须包含
END //DELIMITER ; -- 恢复分隔符
三、参数与返回值
1. 输入参数(仅支持IN)
CREATE FUNCTION fn_calculate_tax(salary DECIMAL(10,2),tax_rate DECIMAL(5,2)
RETURNS DECIMAL(10,2)
BEGINRETURN salary * tax_rate / 100;
END
2. 返回值类型
支持所有MySQL数据类型:
-- 返回字符串
CREATE FUNCTION fn_full_name(first_name VARCHAR(50),last_name VARCHAR(50))
RETURNS VARCHAR(100)
BEGINRETURN CONCAT(first_name, ' ', last_name);
END-- 返回日期
CREATE FUNCTION fn_next_monday()
RETURNS DATE
BEGINRETURN DATE_ADD(CURDATE(), INTERVAL (9 - IF(DAYOFWEEK(CURDATE())=1, 8, DAYOFWEEK(CURDATE()))) DAY);
END
四、变量与流程控制
1. 变量声明与使用
CREATE FUNCTION fn_age_category(age INT)
RETURNS VARCHAR(20)
BEGINDECLARE category VARCHAR(20);IF age < 18 THENSET category = '未成年';ELSEIF age BETWEEN 18 AND 60 THENSET category = '成年';ELSESET category = '老年';END IF;RETURN category;
END
2. 复杂逻辑示例
CREATE FUNCTION fn_inventory_status(quantity INT,threshold INT)
RETURNS VARCHAR(30)
BEGINDECLARE status VARCHAR(30);CASE WHEN quantity <= 0 THENSET status = '缺货';WHEN quantity < threshold THENSET status = '库存不足';ELSESET status = '库存充足';END CASE;RETURN status;
END
五、确定性函数
CREATE FUNCTION fn_discount_price(original_price DECIMAL(10,2),discount DECIMAL(5,2))
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGINRETURN original_price * (1 - discount/100);
END
六、存储函数调用
1. 在SQL中直接调用
-- 基本调用
SELECT fn_calculate_tax(5000, 15) AS tax_amount;-- 与表数据结合使用
SELECT employee_id,salary,fn_calculate_tax(salary, 20) AS tax
FROM employees;-- 在WHERE条件中使用
SELECT *
FROM products
WHERE fn_inventory_status(quantity, 10) = '库存不足';
2. 在存储过程中调用
CREATE PROCEDURE sp_apply_raise(IN emp_id INT)
BEGINUPDATE employeesSET salary = salary * fn_get_raise_factor(department)WHERE id = emp_id;
END
七、管理存储函数
1. 查看函数
-- 查看所有函数
SHOW FUNCTION STATUS;-- 查看函数定义
SHOW CREATE FUNCTION fn_name;
2. 修改函数
-- MySQL需要先删除再重建
DROP FUNCTION IF EXISTS fn_name;
CREATE FUNCTION fn_name() ...
3. 删除函数
DROP FUNCTION [IF EXISTS] fn_name;
八、最佳实践
- 命名规范:建议使用
fn_
前缀区分 - 单一职责:每个函数只完成一个明确功能
- 性能考虑:避免在频繁调用的函数中使用复杂查询
- 错误处理:考虑使用DECLARE HANDLER处理可能错误
- 注释:添加函数目的、参数和返回值说明
🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳🐳
2、存储过程😸
一、存储过程概述
存储过程
是预编译的SQL语句集合
,存储在数据库中,具有以下特点:
- 预编译执行:
首次创建时编译
,后续调用直接执行,效率高 - 减少网络流量:客户端
只需发送调用命令
,而非多条SQL语句 - 增强安全性:可
限制用户对表的直接访问
,通过过程间接操作 - 代码
复用
:一次创建,多次调用,便于维护
二、存储过程语法结构
DELIMITER // -- 修改分隔符(可选)CREATE PROCEDURE 过程名([IN|OUT|INOUT] 参数名 数据类型,...
)
[特性列表]
BEGIN-- 声明部分(DECLARE)-- 执行部分(SQL语句)-- 控制结构(IF/CASE/LOOP等)
END //DELIMITER ; -- 恢复分隔符
三、参数类型详解
1. IN参数(默认)
CREATE PROCEDURE sp_raise_salary(IN emp_id INT,IN raise_amount DECIMAL(10,2)
)
BEGINUPDATE employees SET salary = salary + raise_amountWHERE id = emp_id;
END
2. OUT参数
CREATE PROCEDURE sp_get_employee_stats(OUT max_salary DECIMAL(10,2),OUT min_salary DECIMAL(10,2),OUT avg_salary DECIMAL(10,2)
)
BEGINSELECT MAX(salary), MIN(salary), AVG(salary)INTO max_salary, min_salary, avg_salaryFROM employees;
END
3. INOUT参数
CREATE PROCEDURE sp_increment_counter(INOUT counter INT,IN increment INT
)
BEGINSET counter = counter + increment;
END
四、变量与流程控制
1. 变量声明与使用
CREATE PROCEDURE sp_calculate_bonus(IN emp_id INT)
BEGINDECLARE base_salary DECIMAL(10,2);DECLARE years_service INT;DECLARE bonus DECIMAL(10,2);SELECT salary, DATEDIFF(NOW(), hire_date)/365 INTO base_salary, years_serviceFROM employees WHERE id = emp_id;SET bonus = base_salary * 0.1 * years_service;UPDATE employees SET bonus = bonus WHERE id = emp_id;
END
2. 条件控制(IF/CASE)
CREATE PROCEDURE sp_get_employee_level(IN emp_id INT, OUT level VARCHAR(20))
BEGINDECLARE emp_salary DECIMAL(10,2);SELECT salary INTO emp_salary FROM employees WHERE id = emp_id;IF emp_salary > 10000 THENSET level = '高级';ELSEIF emp_salary > 5000 THENSET level = '中级';ELSESET level = '初级';END IF;
END
3. 循环控制(WHILE/REPEAT/LOOP)
CREATE PROCEDURE sp_generate_test_data(IN num_rows INT)
BEGINDECLARE i INT DEFAULT 1;WHILE i <= num_rows DOINSERT INTO test_table VALUES(i, CONCAT('Item-', i));SET i = i + 1;END WHILE;
END
五、错误处理
CREATE PROCEDURE sp_transfer_funds(IN from_acc INT,IN to_acc INT,IN amount DECIMAL(10,2),OUT status VARCHAR(50)
)
BEGINDECLARE EXIT HANDLER FOR SQLEXCEPTIONBEGINROLLBACK;SET status = '转账失败';END;START TRANSACTION;UPDATE accounts SET balance = balance - amount WHERE account_id = from_acc;UPDATE accounts SET balance = balance + amount WHERE account_id = to_acc;COMMIT;SET status = '转账成功';
END
六、存储过程调用
1. 基本调用
-- 无参数
CALL sp_update_all_salaries();-- IN参数
CALL sp_raise_salary(101, 500.00);-- OUT参数
SET @max = 0, @min = 0, @avg = 0;
CALL sp_get_employee_stats(@max, @min, @avg);
SELECT @max, @min, @avg;-- INOUT参数
SET @counter = 10;
CALL sp_increment_counter(@counter, 5);
SELECT @counter; -- 输出15
2. 在应用程序中调用
// Java示例
try (Connection conn = DriverManager.getConnection(url, user, password);CallableStatement stmt = conn.prepareCall("{call sp_raise_salary(?, ?)}")) {stmt.setInt(1, 101); // 设置第一个IN参数stmt.setBigDecimal(2, new BigDecimal("500.00")); // 设置第二个IN参数stmt.execute();
}
七、管理存储过程
1. 查看存储过程
-- 查看所有存储过程
SHOW PROCEDURE STATUS;-- 查看特定存储过程代码
SHOW CREATE PROCEDURE sp_name;
2. 修改存储过程
-- MySQL中需要先删除再重建
DROP PROCEDURE IF EXISTS sp_name;
CREATE PROCEDURE sp_name() ...
3. 删除存储过程
DROP PROCEDURE [IF EXISTS] sp_name;
八、最佳实践
- 命名规范:使用统一前缀如
sp_
或proc_
- 参数验证:在过程开始验证输入参数有效性
- 注释:添加详细注释说明功能和参数
- 错误处理:为关键操作添加错误处理
- 避免长事务:长时间运行的过程应考虑分批次处理
3、存储函数😸 VS 存储过程😸
🔥 对比表
特性 | 存储函数(FUNCTION) | 存储过程(PROCEDURE) |
---|---|---|
创建关键字 | CREATE FUNCTION | CREATE PROCEDURE |
参数模式 | 仅输入参数(隐式IN ,不可写IN 关键字) | 必须显式声明IN /OUT /INOUT |
返回值 | 必须用RETURNS 声明类型且用RETURN 返回值 | 无RETURNS ,通过OUT 参数或结果集返回数据 |
调用方式 | SELECT func_name() | CALL proc_name() |
能否执行DML | 通常只查询(非严格限制) | 可执行所有SQL(INSERT/UPDATE/DELETE等) |
✅ 存储函数的正确语法
CREATE FUNCTION 函数名(参数1 数据类型, -- 只能这样写,不能加IN/OUT!参数2 数据类型 -- 多个参数用逗号分隔
)
RETURNS 返回值数据类型 -- 必须声明返回类型
[DETERMINISTIC|NOT DETERMINISTIC] -- 可选特性
BEGIN-- 函数体RETURN 值; -- 必须有RETURN语句
END;
示例:计算年龄总和
CREATE FUNCTION sum_ages(dept VARCHAR(50))
RETURNS INT
BEGINDECLARE total INT;SELECT SUM(age) INTO total FROM Employee WHERE department = dept;RETURN total;
END;
调用方式
-- 直接调用
SELECT sum_ages('Sales') AS department_total_age;-- 与其他SQL语句结合使用
SELECT department,sum_ages(department) AS total_age
FROM Employee
GROUP BY department;
✅ 存储过程的正确语法
CREATE PROCEDURE 过程名([IN] 参数1 数据类型, -- IN可省略(默认就是IN)OUT 参数2 数据类型, -- 必须显式声明OUTINOUT 参数3 数据类型 -- 双向参数
)
BEGIN-- 过程体-- 可执行任意SQL,通过OUT参数返回值
END;
示例:获取最老员工信息
CREATE PROCEDURE get_oldest_employee(OUT emp_name VARCHAR(100),OUT emp_age INT
)
BEGINSELECT name, age INTO emp_name, emp_ageFROM Employee ORDER BY age DESC LIMIT 1;
END;
调用方式
-- 第一步:声明用户变量接收OUT参数
SET @oldest_name = '';
SET @oldest_age = 0;-- 第二步:调用存储过程
CALL get_oldest_employee(@oldest_name, @oldest_age);-- 第三步:查看结果
SELECT @oldest_name AS oldest_employee_name, @oldest_age AS oldest_employee_age;--or 显示结果
SELECT CONCAT('最年长员工是: ', @name, ', 年龄: ', @age) AS result;
❌ 常见错误示范
-
在函数中使用OUT参数:
-- 错误!函数不允许OUT参数 CREATE FUNCTION bad_example(OUT x INT)...
-
在过程中省略OUT声明:
-- 错误!参数默认是IN,不会输出值 CREATE PROCEDURE bad_example(result INT)...
-
混淆调用方式:
-- 错误!函数不能用CALL CALL my_function();-- 错误!过程不能用SELECT SELECT my_procedure();
🌟 记忆口诀
函数如
数学公式
:输入→计算→返回单值
过程如操作脚本
:输入/输出→执行多动作→无返回
4、答疑🤔
👆MySQL 存储函数的确定性(DETERMINISTIC)
确定性函数是指:对于相同的输入参数,函数总是返回完全相同的结果,不受外部因素影响。数学函数就是典型的确定性函数,例如:
-- 确定性函数示例
CREATE FUNCTION fn_square(x INT)
RETURNS INT
DETERMINISTIC
BEGINRETURN x * x; -- 输入3永远返回9
END
非确定性函数则可能对相同的输入返回不同结果,例如:
-- 非确定性函数示例
CREATE FUNCTION fn_random_discount()
RETURNS DECIMAL(3,2)
NOT DETERMINISTIC
BEGINRETURN RAND() * 0.5; -- 每次调用返回不同随机值
END
🤔为什么需要声明确定性?
查询优化
。MySQL优化器会对确定性函数进行特殊处理:对于相同参数,可能缓存函数结果;在索引优化时有不同的处理策略。复制环境
要求。在主从复制环境中,非确定性函数可能导致数据不一致。函数索引
限制。只有确定性函数才能用于创建函数索引。
✅ 确定性场景
- 数学计算(加减乘除、幂运算等)
- 字符串处理(拼接、截取、格式化等)
- 日期计算(基于固定公式的计算)
- 业务规则计算(固定折扣率、税率等)
❌ 非确定性场景
- 依赖当前时间(
NOW()
,CURDATE()
) - 使用随机数(
RAND()
) - 调用外部服务(获取实时汇率、天气等)
- 查询数据库(除非查询的表数据绝对不变)
😀特殊注意事项
-
默认行为
如果不声明,MySQL默认
认为函数是NOT DETERMINISTIC
-
错误声明的后果
如果错误地将非确定性函数声明为确定性:
-可能导致查询结果错误
-在复制环境中造成数据不一致
-函数索引返回不正确结果 -
时间函数的特殊处理
-- 虽然包含CURDATE(),但可以声明为DETERMINISTIC
-- 因为同一SQL语句中多次调用返回相同值
CREATE FUNCTION fn_is_birthday_today(birth_date DATE)
RETURNS BOOLEAN
DETERMINISTIC
BEGINRETURN MONTH(birth_date) = MONTH(CURDATE()) AND DAY(birth_date) = DAY(CURDATE());
END
相关文章:
MySQL 存储函数[特殊字符] VS 存储过程[特殊字符]
1、存储函数😸 一、存储函数概述 存储函数是MySQL中一种特殊的存储程序,具有以下特点: 返回单个值:必须通过RETURN语句返回明确的结果SQL表达式使用:可以直接在SQL语句中调用输入参数:只接受输入参数(隐…...
reactor实现TCP遇到的问题和探究
struct conn{ int fd; char rbuffer[1024]; char wbuffer[1024]; int wlength; int rlength; int (*recv_cb)(int); int (*send_cb)(int); }; int (*recv_cb)(int); recv_cb:函数指针的名称*recv_cb:星号 * 表示 recv_cb 是一个指针。(*recv_cb)&#…...
ElasticSearch重启之后shard未分配问题的解决
以下是Elasticsearch重启后分片未分配问题的完整解决方案,结合典型故障场景与最新实践: 一、快速诊断定位 检查集群状态 GET /_cluster/health?pretty # status为red/yellow时需关注unassigned_shards字段值 2.查看未分配分片详情 …...

算法第十八天|530. 二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先
530. 二叉搜索树的最小绝对差 题目 思路与解法 第一想法: 一个二叉搜索树的最小绝对差,从根结点看,它的结点与它的最小差值一定出现在 左子树的最右结点(左子树最大值)和右子树的最左结点(右子树的最小值…...
QMK键盘编码器(Encoder)(理论部分)
QMK键盘编码器(Encoder)(理论部分) 前言 作为一名深耕机械键盘DIY多年的老司机,我发现很多键盘爱好者对QMK编码器的配置总是一知半解。今天我就把多年积累的经验毫无保留地分享给大家,从硬件接线到软件配置,从基础应用到高阶玩法,一文全搞定!保证看完就能让你的编码…...

微服务调试问题总结
本地环境调试。 启动本地微服务,使用公共nacos配置。利用如apifox进行本地代码调试解决调试问题。除必要的业务微服务依赖包需要下载到本地。使用mvn clean install -DskipTests进行安装启动前选择好profile环境进行启动,启动前记得mvn clean清理项目。…...
C++(2)
二、面向对象基础 1. 类与对象 1.1 核心概念 类(Class) 定义:抽象描述具有共同特征和行为的对象模板本质:代码复用的蓝图,定义数据(属性)与操作(行为࿰…...

美SEC主席:探索比特币上市证券交易所
作者/演讲者:美SEC主席Paul S. Atkins 编译:Liam 5月12日,由美国SEC加密货币特别工作组发起的主题为《资产上链:TradFi与DeFi的交汇点》系列圆桌会议如期举行。 会议期间,现任美SEC主席Paul S. Atkins发表了主旨演讲。…...
@Controller 与 @RestController-笔记
1.Controller与RestController对比 Spring MVC 中 Controller 与 RestController 的功能对比: Controller是Spring MVC中用于标识一个类作为控制器的标准注解。它允许处理HTTP请求,并返回视图名称,通常和视图解析器一起使用来渲染页面。而R…...
JavaScript篇:揭秘函数式与命令式编程的思维碰撞
大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了…...
c++和c的不同
c:面向对象(封装,继承,多态),STL,模板 一、基础定义与背景 C语言 诞生年代:20世纪70年代,Dennis Ritchie在贝尔实验室开发。主要特点: 过程式、结构化编程面向系统底层…...

MySQL Join连接算法深入解析
引言 在关系型数据库中,Join操作是实现多表数据关联查询的关键手段,直接影响查询性能和资源消耗。MySQL支持多种Join算法,包括经典的索引嵌套循环连接(Index Nested-Loop Join)、块嵌套循环连接(Block Nes…...
从构想到交付:专业级软开发流程详解
目录 一、软件开发生命周期(SDLC)标准化流程 1. 需求工程阶段(Requirement Engineering) 2. 系统设计阶段(System Design) 3. 开发阶段(Implementation) 4. 测试阶段&a…...
腾讯云-人脸核身+人脸识别教程
一。产品概述 慧眼人脸核身特惠活动 腾讯云慧眼人脸核身是一组对用户身份信息真实性进行验证审核的服务套件,提供人脸核身、身份信息核验、银行卡要素核验和运营商类要素核验等各类实名信息认证能力,以解决行业内大量对用户身份信息真实性核实的需求&a…...

http请求卡顿
接口有时出现卡顿,而且抓包显示有时tcp目标机器没有响应, 但nginx和java应用又没有错误日志,让人抓耳挠腮,最终还是请运维大哥帮忙,一顿操作后系统暂时无卡顿了,佩服的同时感觉疑惑到底调整了啥东…...
使用Vite打包前端Vue项目,碰到依赖包体积大,出现内存溢出的解决办法
vite.config.ts 中 方式一 使用 esbuild build: {outDir: "dist",minify: "esbuild",sourcemap: false,chunkSizeWarningLimit: 5000,rollupOptions: {experimentalLogSideEffects: false,output: {// 最小化拆分包manualChunks(id) {if (id.includes(&q…...
C语言_函数调用栈的汇编分析
在 C 语言的底层实现中,函数调用栈是程序运行时内存管理的核心机制。它不仅负责函数间的控制转移,还管理局部变量、参数传递和返回值。本文将结合 C 语言代码和 x86-64 汇编指令,深入解析函数调用栈的工作原理。 一、函数调用栈的基本概念 函数调用栈是内存中的一块后进先…...
Java Spring Boot 控制器中处理用户数据详解
目录 一、获取请求参数1.1 获取查询参数1.2 获取路径参数 二、处理表单提交2.1 处理表单数据 三、处理 JSON 数据3.1 接收 JSON 数据 四、返回 JSON 数据五、处理文件上传5.1 单文件上传5.2 多文件上传 六、总结 在 Spring Boot 应用开发中,控制器(Contr…...

vite+vue建立前端工程
参考 开始 | Vite 官方中文文档 VUE教程地址 https://cn.vuejs.org/tutorial/#step-1 第一个工程 https://blog.csdn.net/qq_35221977/article/details/137171497 脚本 chcp 65001 echo 建立vite工程 set PRO_NAMEmy-vue-appif not exist %PRO_NAME% (call npm i…...
【Docker】docker login总是报各种超时错误,导致登录不成功。
报错信息:Error response from daemon: Get “https://registry-1.docker.io/v2/”: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).等超时错误。 解决方案:docker login总是报各种超时错…...

vue使用路由技术实现登录成功后跳转到首页
文章目录 一、概述二、使用步骤安装vue-router在src/router/index.js中创建路由器,并导出在vue应用实例中使用router声明router-view标签,展示组件内容 三、配置登录成功后跳转首页四、参考资料 一、概述 路由,决定从起点到终点的路径的进程…...

day20-线性表(链表II)
一、调试器 1.1 gdb(调试器) 在程序指定位置停顿 1.1.1 一般调试 gcc直接编译生成的是发布版(Release) gcc -g //-g调式版本,(体积大,内部有源码)(DeBug&#…...
什么是函数重载?为什么 C 不支持函数重载,而 C++能支持函数重载?
函数重载的定义 函数重载是指在同一作用域内,可以有多个同名函数,但是这些函数的参数列表(参数的个数、类型或顺序)不同。编译器会根据调用函数时传递的实际参数来确定具体调用哪个重载函数。 C不支持函数重载的原因 C语言的编译器…...
Python机器学习笔记(二十二、模型评估-交叉验证)
交叉验证(cross-validation)是一种评估泛化性能的统计学方法,它比单次划分训练集和测试集的方法更加稳定、全面。 在交叉验证中,数据被多次划分,并且需要训练多个模型。最常用的交叉验证是k折交叉验证(k-fold cross-validation),其中k是由用户指定的数字,通常取5或10…...
Python爬虫实战:获取woodo网各类免费图片,积累设计素材
1. 引言 在设计素材收集领域,woodo 网(吾道)提供了大量高质量的设计图片资源。然而,手动下载这些图片效率低下,且难以批量获取。开发自动化爬虫系统能够有效解决这一问题,但面临网站反爬机制、数据去重、并发控制等技术挑战。本文提出的爬虫系统针对 woodo 网站特点进行…...
Go语言运算符详解
文章目录 1. 算术运算符2. 关系运算符3. 逻辑运算符4. 位运算符5. 赋值运算符6. 其他运算符运算符优先级注意事项 Go语言提供了与其他语言类似的运算符,包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符等。这些运算符即可满足基本的运算需求。 1. 算…...

HTTP 连接复用机制详解
文章目录 HTTP 连接复用机制详解为什么需要连接复用?连接复用的实现方式HTTP/1.1 的 Keep-AliveHTTP/2 多路复用 HTTP/1.1 的队头阻塞问题 HTTP 连接复用机制详解 HTTP 连接复用是 HTTP/1.1 及更高版本中的核心优化机制,旨在减少 TCP 连接建立和关闭的开…...

网络协议分析 实验六 TCP和端口扫描
文章目录 实验6.1 TCP(Transfer Control Protocol)练习二 利用仿真编辑器编辑并发送TCP数据包实验6.2 UDP端口扫描实验6.3 TCP端口扫描练习一 TCP SYN扫描练习二 TCP FIN扫描 实验6.1 TCP(Transfer Control Protocol) 建立:syn,syn ack,ack 数据传送:tcp…...

Spring Web MVC————入门(2)
1,请求 我们接下来继续讲请求的部分,上期将过很多了,我们来给请求收个尾。 还记得Cookie和Seesion吗,我们在HTTP讲请求和响应报文的时候讲过,现在再给大家讲一遍,我们HTTP是无状态的协议,这次的…...
Python知识框架
一、Python基础语法 变量与数据类型 变量命名规则 基本类型:int, float, str, bool, None 复合类型:list, tuple, dict, set 类型转换与检查(type(), isinstance()) 运算符 算术运算符:, -, *, /, //, %, ** 比较…...