MySQL-存储过程

什么是存储过程


我们前面所学习的MySQL语句都是针对一个表或几个表的单条 SQL 语句,但是在数据库的实际操作中,并非所有操作都那么简单,经常会有一个完整的操作需要多条SQL语句处理多个表才能完成。例如,为了确认学生能否毕业,需要同时查询学生档案表、成绩表和综合表,此时就需要使用多条 SQL 语句来针对几个数据表完成这个处理要求。存储过程可以有效地完成这个数据库操作。

存储过程是数据库存储的一个重要的功能,但是 MySQL 在 5.0 以前并不支持存储过程,这使得 MySQL 在应用上大打折扣。好在 MySQL 5.0 终于开始已经支持存储过程,这样即可以大大提高数据库的处理速度,同时也可以提高数据库编程的灵活性。

存储过程是一组为了完成特定功能的 SQL 语句集合。使用存储过程的目的是将常用或复杂的工作预先用 SQL语句写好并用一个指定名称存储起来,这个过程经编译和优化后存储在数据库服务器中,因此称为存储过程。当以后需要数据库提供与已定义好的存储过程的功能相同的服务时,只需调用“CALL存储过程名字”即可自动完成。

常用操作数据库的 SQL 语句在执行的时候需要先编译,然后执行。存储过程则采用另一种方式来执行 SQL 语句。

一个存储过程是一个可编程的函数,它在数据库中创建并保存,一般由 SQL 语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的特定功能时,存储过程尤为合适。

存储过程通常有如下优点:

  1. 封装性 存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的 SQL 语句,并且数据库专业人员可以随时对存储过程进行修改,而不会影响到调用它的应用程序源代码。

  1. 可增强 SQL 语句的功能和灵活性 存储过程可以用流程控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。

  1. 可减少网络流量 由于存储过程是在服务器端运行的,且执行速度快,因此当客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而可降低网络负载。

  1. 高性能 存储过程执行一次后,产生的二进制代码就驻留在缓冲区,在以后的调用中,只需要从缓冲区中执行二进制代码即可,从而提高了系统的效率和性能。

  1. 提高数据库的安全性和数据的完整性 使用存储过程可以完成所有数据库操作,并且可以通过编程的方式控制数据库信息访问的权限。

创建存储过程


MySQL 存储过程是一些 SQL 语句的集合,比如有的时候我们可能需要一大串的 SQL 语句,或者说在编写 SQL语句的过程中还需要设置一些变量的值,这个时候我们就完全有必要编写一个存储过程。下面我们来介绍一下如何创建一个存储过程。 基本语法 可以使用 CREATE PROCEDURE 语句创建存储过程。

语法格式如下:

CREATE PROCEDURE <过程名> ( [过程参数[,…] ] ) <过程体> [过程参数[,…] ] 格式 [ IN | OUT | INOUT ] <参数名> <类型>

语法说明如下:

  1. 过程名 存储过程的名称,默认在当前数据库中创建。若需要在特定数据库中创建存储过程,则要在名称前面加上数据库的名称,即 db_name.sp_name。需要注意的是,名称应当尽量避免选取与 MySQL 内置函数相同的名称,否则会发生错误。

  1. 过程参数 存储过程的参数列表。其中,<参数名>为参数名,<类型>为参数的类型(可以是任何有效的MySQL 数据类型)。当有多个参数时,参数列表中彼此间用逗号分隔。存储过程可以没有参数(此时存储过程的名称后仍需加上一对括号),也可以有 1 个或多个参数。MySQL 存储过程支持三种类型的参数,即输入参数、输出参数和输入/输出参数,分别用 IN、OUT 和 INOUT三个关键字标识。其中,输入参数可以传递给一个存储过程,输出参数用于存储过程需要返回一个操作结果的情形,而输入/输出参数既可以充当输入参数也可以充当输出参数。需要注意的是,参数的取名不要与数据表的列名相同,否则尽管不会返回出错信息,但是存储过程的 SQL 语句会将参数名看作列名,从而引发不可预知的结果。

  1. 过程体 存储过程的主体部分,也称为存储过程体,包含在过程调用的时候必须执行的 SQL 语句。这个部分以关键字 BEGIN 开始,以关键字 END 结束。若存储过程体中只有一条 SQL 语句,则可以省略 BEGINEND 标志。在存储过程的创建中,经常会用到一个十分重要的 MySQL 命令,即 DELIMITER 命令,特别是对于通过命令行的方式来操作 MySQL 数据库的使用者,更是要学会使用该命令。在 MySQL 中,服务器处理 SQL 语句默认是以分号作为语句结束标志的。然而,在创建存储过程时,存储过程体可能包含有多条 SQL 语句,这些 SQL 语句如果仍以分号作为语句结束符,那么 MySQL 服务器在处理时会以遇到的第一条 SQL 语句结尾处的分号作为整个程序的结束符,而不再去处理存储过程体中后面的 SQL 语句,这样显然不行。为解决这个问题,通常可使用 DELIMITER 命令将结束命令修改为其他字符。

语法格式如下:

DELIMITER $$

语法说明如下: $$ 是用户定义的结束符,通常这个符号可以是一些特殊的符号,如两个“?”或两个“¥”等。 当使用 DELIMITER 命令时,应该避免使用反斜杠“\”字符,因为它是 MySQL 的转义字符。

在 MySQL 命令行客户端输入如下SQL语句。

mysql > DELIMITER ??

成功执行这条 SQL 语句后,任何命令、语句或程序的结束标志就换为两个问号“??”了。

若希望换回默认的分号“;”作为结束标志,则在 MySQL 命令行客户端输入下列语句即可:

mysql > DELIMITER ;

注意:DELIMITER 和分号“;”之间一定要有一个空格。在创建存储过程时,必须具有 CREATE ROUTINE 权限。可以使用 SHOW PROCEDURE STATUS 命令查看数据库中存在哪些存储过程,若要查看某个存储过程的具体信息,则可以使用 SHOW CREATE PROCEDURE <存储过程名>。

创建不带参数的存储过程

【实例 1】创建名称为 ShowStuScore 的存储过程,存储过程的作用是从学生成绩信息表中查询学生的成绩信息,输入的 SQL 语句和执行过程如下所示。

mysql> DELIMITER //
mysql> CREATE PROCEDURE ShowStuScore()
 -> BEGIN
 -> SELECT * FROM tb_students_score;
 -> END //
Query OK, 0 rows affected (0.09 sec)

创建存储过程 ShowStuScore 后,通过 CALL 语句调用该存储过程的 SQL 语句和执行结果如下所示。

mysql> DELIMITER ;
mysql> CALL ShowStuScore();
+--------------+---------------+
| student_name | student_score |
+--------------+---------------+
| Dany | 90 |
| Green | 99 |
| Henry | 95 |
| Jane | 98 |
| Jim | 88 |
| John | 94 |
| Lily | 100 |
| Susan | 96 |
| Thomas | 93 |
| Tom | 89 |
+--------------+---------------+
10 rows in set (0.00 sec)
Query OK, 0 rows affected (0.02 sec)

创建带参数的存储过程

【实例 2】创建名称为 GetScoreByStu 的存储过程,输入参数是学生姓名。存储过程的作用是通过输入的学生姓名从学生成绩信息表中查询指定学生的成绩信息,输入的 SQL 语句和执行过程如下所示。

mysql> DELIMITER //
mysql> CREATE PROCEDURE GetScoreByStu
 -> (IN name VARCHAR(30))
 -> BEGIN
 -> SELECT student_score FROM tb_students_score
 -> WHERE student_name=name;
 -> END //
Query OK, 0 rows affected (0.01 sec)

创建存储过程 GetScoreByStu 后,通过 CALL 语句调用该存储过程的 SQL 语句和执行结果如下所示。

mysql> DELIMITER ;
mysql> CALL GetScoreByStu('Green');
+---------------+
| student_score |
+---------------+
| 99 |
+---------------+
1 row in set (0.03 sec)
Query OK, 0 rows affected (0.03 sec)

修改存储过程


在实际开发过程中,业务需求修改的情况时有发生,这样,不可避免的需要修改 MySQL 中存储过程的特征 。基本语法 可以使用 ALTER PROCEDURE 语句修改存储过程的某些特征。

语法格式如下:

ALTER PROCEDURE <过程名> [ <特征> … ]

提示:这个语法用于修改存储过程的某些特征,如要修改存储过程的内容,可以先删除该存储过程,再重新创建。

修改存储过程的内容和名称 修改存储过程的内容可以通过删除原存储过程,再以相同的命名创建新的存储过

程。

修改存储过程的名称可以通过删除原存储过程,再以不同的命名创建新的存储过程。

删除存储过程


当 MySQL 数据库中存在废弃的存储过程是,我们需要将它从数据库中删除。 基本语法 存储过程被创建后,保存在数据库服务器上,直至被删除。可以使用 DROP PROCEDURE 语句删除数据库中已创建的存储过程。

语法格式如下:

DROP { PROCEDURE | FUNCTION } [ IF EXISTS ] <过程名>

语法说明如下:

  1. 过程名 指定要删除的存储过程的名称。

  1. IF EXISTS 指定这个关键字,用于防止因删除不存在的存储过程而引发的错误。 注意:存储过程名称后面没有参数列表,也没有括号,在删除之前,必须确认该存储过程没有任何依赖关系,否则会导致其他与之关联的存储过程无法运行。

删除存储过程 删除存储过程 GetScoreByStu,查看存储过程的运行结果如下所示。

mysql> DROP PROCEDURE GetScoreByStu;
Query OK, 0 rows affected (0.00 sec)
mysql> CALL GetScoreByStu('Green');
ERROR 1305 (42000): PROCEDURE test_db.GetScoreByStu does not exist

判断存储过程


IF

语法如下:

CREATE
    PROCEDURE sp_name ([proc_parameter[,...]])
    routine_body

proc_parameter:
    [ IN | OUT | INOUT ] param_name type

routine_body:
    Valid SQL routine statement

IF search_condition THEN statement_list
    [ELSEIF search_condition THEN statement_list] ...
    [ELSE statement_list]
END IF

创建一个student表并插入三条数据

mysql> create table student(
    -> id int,
    -> name varchar(30),
    -> score float);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into student values(1,'z3',30),(2,'l4',60),(3,'w5',90);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

创建存储过程,输入“a”返回大于等于60分数的学生信息,输入“b”返回大于等于80分数的学生信息,输入“c”返回大于等于90分数的学生信息,输入其他字符串则返回全部学生信息。

mysql> delimiter $$
mysql> create procedure t1(in chars varchar(10))
    -> begin
    -> if chars="a" then
    -> select * from student where score>=60;
    -> elseif chars="b" then
    -> select * from student where score>=80;
    -> elseif chars="c" then
    -> select * from student where score>=90;
    -> else select * from student;
    -> end if;
    -> end $$
Query OK, 0 rows affected (0.08 sec)

mysql> delimiter ;
mysql> call t1("a");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    2 | l4   |    60 |
|    3 | w5   |    90 |
+------+------+-------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

mysql> call t1("b");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    3 | w5   |    90 |
+------+------+-------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call t1("c");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    3 | w5   |    90 |
+------+------+-------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call t1("abc");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    1 | z3   |    30 |
|    2 | l4   |    60 |
|    3 | w5   |    90 |
+------+------+-------+
3 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

CASE

语法如下:

CREATE
    PROCEDURE sp_name ([proc_parameter[,...]])
    routine_body

proc_parameter:
    [ IN | OUT | INOUT ] param_name type

routine_body:
    Valid SQL routine statement

CASE case_value
    WHEN when_value THEN statement_list
    [WHEN when_value THEN statement_list] ...
    [ELSE statement_list]
END CASE

同样,上面使用的if语法创建存储过程,这次使用case语法创建。输入“a”返回大于等于60分数的学生信息,输入“b”返回大于等于80分数的学生信息,输入“c”返回大于等于90分数的学生信息,输入其他字符串则返回全部学生信息。

mysql> create procedure t2(in chars varchar(10))
    -> begin
    -> case chars
    -> when "a" then select * from student where score>=60;
    -> when "b" then select * from student where score>=80;
    -> when "c" then select * from student where score>=90;
    -> else select * from student;
    -> end case;
    -> end$$
Query OK, 0 rows affected (0.01 sec)

mysql> delimiter ;
mysql> call t2("a");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    2 | l4   |    60 |
|    3 | w5   |    90 |
+------+------+-------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call t2("b");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    3 | w5   |    90 |
+------+------+-------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call t2("c");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    3 | w5   |    90 |
+------+------+-------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> call t2("d");
+------+------+-------+
| id   | name | score |
+------+------+-------+
|    1 | z3   |    30 |
|    2 | l4   |    60 |
|    3 | w5   |    90 |
+------+------+-------+
3 rows in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

循环存储过程


WHILE

语法如下:

CREATE
    PROCEDURE sp_name ([proc_parameter[,...]])
    routine_body

proc_parameter:
    [ IN | OUT | INOUT ] param_name type

routine_body:
    Valid SQL routine statement

Name: 'DECLARE VARIABLE'
Description:
Syntax:
DECLARE var_name [, var_name] ... type [DEFAULT value]

Syntax:
WHILE search_condition DO
    statement_list
END WHILE

创建循环存储过程,实现1+2+3+4...100(我算过了和为5050)while先判断后执行(条件满足情况下,则执行循环体内容,不满足,则结束循环),详情看下面命令吧。

mysql> create procedure t3()
    -> begin
    -> declare num int default 0;            #定义num默认值为0
    -> declare summ int default 0;            #定义summ默认值为0
    -> while num<=100 do                    #num小于等于100后停止
    -> set summ=summ+num;                    #第一次循环为0,第二次为num上次循环的结果
    -> set num=num+1;                        #num+1继续循环
    -> end while;                            #跳过满足循环后跳出
    -> select summ;                            #打印出summ循环相加的结果
    -> end $$                                #结束
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;
mysql> call t3();
+------+
| summ |
+------+
| 5050 |
+------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

上面的命令虽然实现了循环,但是局限性很大只能打印出加到100,也就是说每次打印的都是5050,如果这次我们需要的更多呢?下面可以使用参数代替。

mysql> delimiter $$
mysql> create procedure t4(in a int)
    -> begin
    -> declare num int default 0;
    -> declare summ int default 0;
    -> while num<=a do
    -> set summ=summ+num;
    -> set num=num+1;
    -> end while;
    -> select summ;
    -> end $$
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;
mysql> call t4(10);
+------+
| summ |
+------+
|   55 |
+------+
1 row in set (0.01 sec)

Query OK, 0 rows affected (0.01 sec)

mysql> call t4(1000);
+--------+
| summ   |
+--------+
| 500500 |
+--------+
1 row in set (0.01 sec)

Query OK, 0 rows affected (0.01 sec)

REPEAT

语法如下:

CREATE
    PROCEDURE sp_name ([proc_parameter[,...]])
    routine_body

proc_parameter:
    [ IN | OUT | INOUT ] param_name type

routine_body:
    Valid SQL routine statement

    Syntax:
REPEAT
    statement_list
UNTIL search_condition
END REPEAT

下面的循环也是根据1+2+3...+100,但是和while不同的是repeat的结构是先执行后判断(先执行相关操作 ,再判断是否满足条件,满足,结束循环)。

mysql> delimiter $$
mysql> create procedure t5(in a int)
    -> begin
    -> declare num int default 0;
    -> declare summ int default 0;
    -> repeat
    -> set summ=summ+num;
    -> set num=num+1;
    -> until num>a end repeat;
    -> select summ;
    -> end $$
Query OK, 0 rows affected (0.05 sec)

mysql> delimiter ;
mysql> call t5(10);
+------+
| summ |
+------+
|   55 |
+------+
1 row in set (0.02 sec)

Query OK, 0 rows affected (0.03 sec)

mysql> call t5(100);
+------+
| summ |
+------+
| 5050 |
+------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

学习不是一两天的事,活到老学到老,坚持下去总有一天会有成果。MySQL专栏持续更新,对你有帮助的话收藏起来吧!

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

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

相关文章

归并排序和快速排序

目录 归并排序 思路&#xff1a; 代码执行&#xff1a; 快速排序 运行流程图&#xff1a; 代码思路&#xff1a; 代码执行&#xff1a; 归并排序 定义&#xff1a;归并排序是建立在归并操作上的一种有效&#xff0c;稳定的排序算法&#xff0c;该算法是采用分治法&#x…

【JavaSE】类和对象(中)

类和对象&#xff08;中&#xff09;4. this引用4.1 为什么要有this引用4.2 什么是this引用4.3 this引用的特性5. 对象的构造及初始化5.1 如何初始化对象5.2 构造方法&#xff08;构造器&#xff09;5.2.1 概念5.2.2 特性5.3 默认初始化5.4 就地初始化6. 封装6.1 封装的概念6.2…

常用hook

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。理解&#xff1a;hook是react提供的函数API官方提供的hook基础hookuseState APIconst [state, setState] useState(initialState); //返回state值 以及更新state的方法 …

壹沓科技完成近2亿元B轮融资:构建数字机器人,实现业务超自动化

RPA中国获悉&#xff0c;全球领先的数字机器人公司壹沓科技近期宣布完成近2亿元B轮融资&#xff0c;本轮融资由鼎晖VGC(创新与成长基金)领投&#xff0c;创享欢聚投资基金、IDG资本、钟鼎资本跟投&#xff0c;指数资本继续担任独家财务顾问。 壹沓科技CEO卞晓瑜表示&#xff1…

栈、队列、优先级队列的模拟实现

优先级队列的模拟实现栈stack的模拟实现push()pop()top()size()empty()swap()stack总代码队列queue的模拟实现push()pop()front()back()empty()size()swap()queue总代码优先级队列(堆)push()pop()top()empty()size()swap()priority_queue总代码deque的了解栈 在CSTL中栈并不属…

吃透Java面试题,建议收藏

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

LeetCode:27. 移除元素

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340;算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 一、&#x1f331;27. 移除元素 题目描述&#xff1a;给你一个数组 nums 和一个值 val&am…

Chapter6.2:其他根轨迹及综合实例分析

该系列博客主要讲述Matlab软件在自动控制方面的应用&#xff0c;如无自动控制理论基础&#xff0c;请先学习自动控制系列博文&#xff0c;该系列博客不再详细讲解自动控制理论知识。 自动控制理论基础相关链接&#xff1a;https://blog.csdn.net/qq_39032096/category_10287468…

使用vite创建vue3工程

定义 什么是vite&#xff1f;-----新一代前端构建工具 优势 开发环境中&#xff0c;无需打包操作&#xff0c;可快速的冷启动---最牛的地方轻量快速的热重载&#xff08;HMR&#xff09;---一修改代码就局部刷新&#xff0c;webpack也具备&#xff0c;但vite更快真正的按需编…

【数据结构与算法】用队列实现栈

文章目录&#x1f60e;前言如何用队列实现栈&#xff1f;用队列实现栈整体的实现代码&#x1f60e;写在最后&#x1f60e;前言 &#x1f63c;前面我们相继实现了 栈 和 队列 &#xff0c;是不是愁没有练手的地方呢&#xff1f;别担心&#xff0c;本章带大家用队列来实现一个栈&…

synchronized 加锁 this 和 class 的区别

synchronized 是 Java 语言中处理并发问题的一种常用手段&#xff0c;它也被我们亲切的称之为“Java 内置锁”&#xff0c;由此可见其地位之高。然而 synchronized 却有着多种用法&#xff0c;当它修饰不同对象时&#xff0c;其意义也是不同的&#xff0c;下面我们一起来看。 ​…

云原生时代顶流消息中间件Apache Pulsar部署实操之Pulsar IO与Pulsar SQL

文章目录Pulsar IO (Connector连接器)基础定义安装Pulsar和内置连接器连接Pulsar到Cassandra安装cassandra集群配置Cassandra接收器创建Cassandra Sink验证Cassandra Sink结果删除Cassandra Sink连接Pulsar到PostgreSQL安装PostgreSQL集群配置JDBC接收器创建JDBC Sink验证JDBC …

【网络】网络层协议——IP

目录网络层IP协议IP基础知识IP地址IP报头格式网段划分CIDR特殊的IP地址IP地址的数量限制私有IP地址和公有IP地址路由IP总结网络层 在复杂的网络环境中确定一个合法的路径。 IP协议 IP协议作为整个TCP/IP中至关重要的协议&#xff0c;主要负责将数据包发送给最终的目标计算机…

多线程 (六) 单例模式

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

蓝桥杯刷题冲刺 | 倒计时19天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.抓住那头牛2.排列序数1.抓住那头牛 题目 链接&#xff1a; 抓住那头牛 - C语言网 (dotcpp.com…

网络安全之防火墙

目录 网络安全之防火墙 路由交换终归结底是联通新设备 防御对象&#xff1a; 定义&#xff1a; 防火墙的区域划分&#xff1a; 包过滤防火墙 --- 访问控制列表技术 --- 三层技术 代理防火墙 --- 中间人技术 --- 应用层 状态防火墙 --- 会话追踪技术 --- 三层、四层 UTM …

CrossOver零知识学习1 —— 初识

本文部分内容参考CrossOver22全新版功能简介 免费mac虚拟机工具_CoCo玛奇朵的博客-CSDN博客 特此致谢&#xff01; 一、CrossOver简介 CrossOver是由CODE WEAVERS公司开发的类虚拟机软件&#xff0c;目的是使Linux和Mac OS X操作系统和Window系统兼容。CrossOver英文原意为“…

强烈推荐:0基础入门网安必备《网络安全知识图谱》

蚁景网安学院一直专注于网安实战技能培养&#xff0c;提供全方位的网安安全学习解决方案。我们集聚专业网安技术大佬资源&#xff0c;倾力打造了这本更全面更系统的“网络安全知识图谱”&#xff0c;让大家在网络安全学习路上不迷茫。 在这份网安技能地图册里&#xff0c;我们对…

01 | Msyql系统架构

目录MySQL系统架构连接器查询缓存分析器优化器执行器MySQL系统架构 大体来说&#xff0c;MySQL分为Server层和引擎层两部分。 Server层包含链接器、查询缓存、分析器、优化器和执行器&#xff0c;而引擎层负责的是数据的存储和读取&#xff0c;支持InnoDB、Myisam、Memory等多…

CSS实现文字凹凸效果

使用两个div分别用来实现凹凸效果&#xff1b;text-shadow语法 text-shadow: h-shadow v-shadow blur color; h-shadow&#xff1a;必需。水平阴影的位置。允许负值。 v-shadow &#xff1a;必需。垂直阴影的位置。允许负值。 blur&#xff1a;可选&#xff0c;模糊的距离。 co…