0.参考资料
参考书籍《深入浅出MySQL数据库开发、优化与管理维护》
参考视频《传智播客MySQL》
1.存储过程的简单用法
1)存储过程简介及创建:
- 存储过程简称为过程,procedure,是一种用来处理数据的方式。
存储过程是没有返回值的函数。各种操作都和函数类似(无返回值)。 - 创建存储过程:
Create procedure 过程名称([参数列表]) Begin -- 过程体 End
- 创建测试:
测试结果:delimiter $$ CREATE PROCEDURE pro1() BEGIN -- 过程中需要显式数据时需要用select SELECT * FROM m_class1; END $$ delimiter ;
2)存储过程的查看及调用:
- 函数的查看方式完全适用于过程,关键字改为perocedure。
查看过程:
测试:show procedure status [like '...']\G
- 查看过程创建语句:
测试:show create procedure 过程名;
- 调用存储过程:
过程没有返回值,说明不能用select访问。select调用时只会访问函数。
存储过程的调用(使用专门的关键字call):
测试:call 过程名([参数列表]);
3)存储过程的删除:
- 存储过程一般不能修改内容,只能先删除后增加(可以修改特征值,属性)。
- 删除语法:
测试:drop procedure 过程名;
4)存储过程参数:
- 函数的参数需要指定数据类型,过程比函数更加严格。
过程还有自己的类型限定:三种类型- in:数据只是从外部传入到内部使用(值传递),可以是数据也可以是变量
- Out:只允许过程内部使用(不用外部数据),给外部使用(引用传递:外部的数据会被清空后才进入到内部,存值后可在外部使用),只允许是变量。
- InOut:外部的可以在内部使用,内部修改也可以在外部使用:典型的引用传递,只能穿变量。
- 基本创建方法:
不代表in/out/inout三个都要,只是有的话必须这样写:create procedure 过程名(in 形参 数据类型,out 形参 数据类型,inout 形参 数据类型); Begin -- 过程内容 END
in 形参 数据类型
测试创建: - 调用含参数的存储过程:
注意:out和inout传参时必须要传入一个变量,而不是数值call 过程名(参数列表);
使用如下代码测试:
测试结果:CALL pro2(1,2,3); -- 未传变量 set @int_1:=1; set @int_2:=2; set @int_3:=3; SELECT @int_1,@int_2,@int_3; CALL pro2(@int_1,@int_2,@int_3); SELECT @int_1,@int_2,@int_3;
- out和inout是一种引用传递,内部修改一定会影响外部。
out的值传入过程内部时会被置空。
5)存储过程对变量操作是滞后的:
- 滞后:在存储过程结束的时候才会重新将内部修改的值传入给全局变量。
- 测试代码:
创建存储过程:delimiter $$ CREATE PROCEDURE pro3(in int_1 int,out int_2 int,inout int_3 int) BEGIN -- 查看局部变量 SELECT int_1,int_2,int_3; -- 修改局部变量 SET int_1=100; SET int_2=1000; SET int_3=10000; -- 查看局部变量 SELECT int_1,int_2,int_3; -- 查看全局变量 SELECT @int_1,@int_2,@int_3; -- 修改全局变量(但是最后会被局部变量覆盖) SET @int_1='a'; SET @int_2='b'; SET @int_3='c'; -- 再次查看全局变量 SELECT @int_1,@int_2,@int_3; END $$ delimiter ;
测试代码:set @int_1=1; set @int_2=2; set @int_3=3; CALL pro3(@int_1,@int_2,@int_3); -- 存储过程结束后将out/inout的局部变量返回给全局变量 SELECT @int_1,@int_2,@int_3;
- 存储过程没有返回值但是同样可以将内部的结果返回给外部使用。
2.存储过程的补充
存储过程及函数的基础补充
1)存储过程和函数基础知识补充(简单看一看就行):
- 存储过程和函数是经过实现编译并存储在数据库中的SQL语句集合,调用存储过程可以简化应用开发人员的工作,减少数据在数据库和应用服务器之间的传输,有利于提高数据处理的效率。
- 存储过程和函数的最大区别在于函数需要返回值而储存过程不需要,返回值。函数的参数类型只能为in类型,而存储过程的参数类型可以为in,out,inout三种类型。
- 函数与存储过程中都允许包含DDL语句。
存储过程中能够执行啊事务的提交及回滚等。
存储过程和函数中决不允许执行LOAD DATA INFILE语句。
存储过程和函数中可以调用其他存储过程和函数。 - 各种操作所需要的权限:
创建存储过程和函数:需要Create Routine权限
修改存储过程和函数(特征值):需要Alter Routine权限
执行存储过程:需要EXECUTE权限
2)含特征值(属性)的函数/存储过程的创建及修改:
- 含特征值的函数/存储过程创建(以存储过程为例):
delimiter $$ create procedure 过程名 (参数列表) [特征值列表] Begin -- 过程体 End $$ delimiter ;
- 特征值列表的选项:
LANGUAGE SQL,[NOT] DETERMINISTIC,
{CONTAINS SQL|NO SQL|READS SQL DATA|MODIFILES SQL DATA}
|SQL SECURITY {DEFINER|INVOKER}|COMMENT ‘string’
如果要指定多个属性选项,不要用逗号也不要用丨,只需要加空格就可以: - 修改存储过程或函数的属性,特征值。
Alter procedure/function 过程/函数名 [特征值列表]
- 各特征值(属性简介):
- LANGUAGE SQL:系统默认的,说明函数/过程体内的语句是用SQL编写的。是为Mysql支持非SQL语言而准备的。
- [NOT] DETERMINISTIC:
DETERMINISTIC
:确定的,每次输入一样输出也一样的程序。NOT DETERMINISTIC
:默认,非确定的。 - {CONTAINS SQL|NO SQL|READS SQL DATA|MODIFILES SQL DATA}:
四个只能选择一个。提供子程序使用数据的内在信息,目前只是提供给服务器,没有根据这些值实际使用数据的情况:CONTAINS SQL
:默认,表示子程序不包含读或者写数据的语句。NO SQL
:子程序不包含SQL语句BEAD SQL DATA
:表示子程序包含读数据的语句但是不包含写数据的语句。MODIFILES SQL DATA
:表示子程序包含写数据的语句。
- SQL SECURITY {DEFINER|INVOKER}:
可以用来指定子程序用创建子程序者的权限来执行(difiner),还是使用调用者的权限来执行(invoker) - COMMENT:存储过程或者函数的注释信息。
- 特征值补充:
上述的子程序其实就是存储过程或者函数BEGIN~END包含的程序体。
DEFINER/INVOKER的权限表示存储过程内的语句权限与创建者/调用者的相同,如果创建者没有对表A的查询权限,而调用者有,则调用者调用SQL SECURITY DEFINER的存储过程时会报错说权限不够,而调用SQL SECURITY INVOKER的存储过程则不会报错。
定义条件和处理
1)定义条件:
- 条件和处理可以用来定义在存储过程中遇到相应问题时的处理步骤。
- 条件的定义语法:
DECLARE 条件名 CONDITION FOR 条件值(condition_value);
- 关于condition_value(条件值)可以填的数:
如一条错误出现,都是这种形式:
定义该错误的条件则condition_value处可以填:SQLSTATE '42000'
(SQLSTATE[VALUE] sqlstate值)
或者1064
(mysql错误值)
2)定义条件的处理:
- 语法:
DECLARE 处理选项 HANDLER FOR condition_value[...] 处理语句;
- 处理选项:
有三种可选值,但是只支持两种:undo不支持CONTINUE
:表示继续执行下面的语句;EXIT
:表示终止语句执行 - condition_value[…] (条件值列表):
有六种值:SQLSTATE[VALUE] sqlstate值
:和条件定义相同- mysql错误码,和条件定义相同
- 条件名,使用条件定义语句定义的条件名
SQLWARNING
:对所有以01开头的代码SQLSTATE代码的速记NOT FOUND
:对所有以02开头的代码SQLSTATE代码的速记SQLEXCEPTION
:对所有没有被SQLWARNING
和NOT FOUND
捕获的(不以以01或02开头的)SQLSTATE代码的速记
- 处理语句:
出现指定错误时的处理语句。原本出错的那条语句不会生效改为指向这条处理语句。
3)条件处理的测试
- 未设置条件处理的情况:
发现报错,根据该错误设置条件处理。 - 设置了条件处理的情况:
出错语句后的语句正常执行。 - 将条件处理器改为以下三种情况和上述条件处理是等价的。
-- 使用sql错误码 DECLARE CONTINUE HANDLER FOR 1062 SET @x2=666; -- 使用条件名 DECLARE DuplicateKey CONDITION FOR 1062 ; DECLARE CONTINUE HANDLER FOR DuplicateKey SET @x2=666; -- 使用速记 DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @x2=666;
游标(光标)的使用
- 光标(游标)简介:
也叫游标,在存储过程和函数中能使用光标对结果集进行循环处理。
是一种用于轻松处理多行数据的机制。
数据量非常大,则需要使用光标来逐条读取查询结果集中的记录 。 - 光标的基本操作:
声明光标:
打开光标:DECLARE 光标 CURSOR FOR select语句;
获取光标:OPEN 光标名;
关闭光标:FETCH 光标名 Into 变量1[,变量2...];
如果没有明确的关闭光标,它会在其声明的复合语句的末尾被关闭。CLOSE 光标名;
游标使用测试:
设计一个存储过程统计m_stu1表年龄大于25岁的人的身高总和:-- 光标测试 delimiter $$ CREATE PROCEDURE cur1() BEGIN -- 定义相关的变量(一定要和结果集字段区分开) DECLARE m_age TINYINT UNSIGNED; DECLARE m_height TINYINT UNSIGNED; -- 声明游标,加不加括号无所谓 DECLARE cur_m_stu1 CURSOR FOR (SELECT age,height FROM m_stu1); -- 定义退出循环的条件处理 DECLARE EXIT HANDLER FOR NOT FOUND CLOSE cur_m_stu1; -- 定义全局变量 SET @sum=0; -- 打开光标 OPEN cur_m_stu1; -- 死循环获取光标内的值 REPEAT -- 获取光标内的一条数据并赋值给局部变量,并指向下一条,不重复取 FETCH cur_m_stu1 INTO m_age,m_height; IF m_age >= 25 THEN SET @sum=@sum+m_height; END IF; -- 死循环条件,使用HANDLER条件处理来退出 UNTIL 0 END REPEAT; CLOSE cur_m_stu1; END $$ delimiter ; CALL cur1(); SELECT @sum;
测试结果:
- 测试中总结游标使用时的注意事项:
FETCH获取游标给变量赋值时变量的数量,顺序(以及数据类型)一定要和声明时的select语句查询的结果集字段相同,否则会报错。
这是上述代码使用select * from m_stu1
时的错误:
还有一个低级错误,变量名不能和字段名相同,否则不报错,但是变量一直取不到值,这是我卡了好长时间的代码:
3.事件调度器(事件)的基本用法
1)事件简介,创建及查看:
- 事件调度器是MySQL5.1后新增的功能,可以让数据库按照自定义的时间周期触发某种操作,可以理解为时间触发器。(书上只有基本用法,更加高大上的用法以后再学)
简单的创建语法:
CREATE EVENT 事件名字 ON SCHEDULE EVERY 时间间隔 STARTS 开始时间 DO 要执行的SQL操作;
详细的创建语法:
CREATE [DEFINER = { user | CURRENT_USER }] EVENT [IF NOT EXISTS] event_name ON SCHEDULE schedule [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] DO event_body; schedule: AT timestamp [+ INTERVAL interval] ... | EVERY interval [STARTS timestamp [+ INTERVAL interval] ...] [ENDS timestamp [+ INTERVAL interval] ...] interval: quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
- 测试:
创建一个m_stu2表:
创建事件调度器:CREATE TABLE `m_stu2` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(20) DEFAULT NULL COMMENT '学生姓名', `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
创建结果:-- 时间调度器 CREATE EVENT add_stu ON SCHEDULE EVERY 10 SECOND DO INSERT INTO m_stu2 VALUES(NULL,'test',NOW());
- 如上图,查看事件创建语句:
查看事件:SHOW CREATE EVENT 事件名;
查看事件的全局设置(默认关闭):SHOW EVENTS;
测试:SHOW VARIABLES LIKE '%scheduler%';
2)事件开启,关闭与删除:
- 事件环境:
事件全局环境是默认关闭的:SHOW VARIABLES LIKE '%scheduler%'
查看,
所有的事件都是使用这一个变量。
可以使用如下代码开启环境:
关闭全局环境:set global event_scheduler = on; -- 或者=1
set global event_scheduler = OFF; -- 或者=0
- 事件开启以关闭
事件是默认开启的,上述的status=ENABLED
。所以只要开启全局环境就可以运行事件了。如果发现是disabled
关闭的可以这样开启:
关闭事件:alter event 事件名 enable;
alter event 事件名 disable;
- 事件开启后的进程:
事件不用主动使用,开启后就自动产生一个后台进程,可以使用:
查看。SHOW PROCESSLIST;
使用SHOW PROCESSLIST\G
查看: - 开启后隔几秒查看数据库,发现已经开始添加数据了,并且间隔为10秒:
- 为了防止表变得很大,创建一个新的调度器,每隔一段清空一次表:
非常适合定期清空临时表或者日志表。CREATE EVENT tunc_stu ON SCHEDULE EVERY 10 MINUTE DO TRUNCATE TABLE m_stu2;
- 事件的删除:
不想使用事件时可以禁用或者直接删除。drop event 事件名;
3)事件调度器的优势,使用场景及注意事项:
- 优势:
MySQL事件调度器部署在数据库内部由DBA或专人统一维护和管理,避免将一些数据库相关的定时任务部署在操作系统层,减少操作系统管理员产生误差操作的风险,对后续的管理和维护也非常有益。 - 适用场景:
适用于定期收集统计信息,定期清理历史数据,定期数据库检查等 - 注意事项:
在繁忙且要求性能的数据库服务器上要慎重部署和启用调度器。
过于复杂的处理更适合用程序实现。
开启和关闭事件调度器需要超级管理员权限。
4.字符集与校对集
1)字符集/校对集概述:
- 简单的说字符集就是一套文字符号及其编码、比较规则的集合。
- 各种字符集的比较:
UTF8的汉字占三个字节。 - Mysql支持多种字符集,一台服务器,一个数据库甚至同一个表不同字段都可以指定不同的字符集。
- 查看所有可用的字符集:
或者使用:show character set;
会显示出所有的字符集和改字符集默认的校对集。select * from information_schema.character_sets;
2)校对集和字符集的选择
- 校对集:
字符集(CHARACTER)用来定义MySQL存储字符串的方式。
校对集(COLLATION)用来定义字符串的比较方式。
字符集和校对集是一对多的关系。
可以使用:
的方式查看。show collation like '%字符集%';
- 校对集的比较:
通常由字符集_语言名_结束标识
组成:
结尾是_cs:最常用,大小写不敏感
结尾是_ci:大小写敏感
结尾是_bin:大小写敏感,二元,比较的是编码,与语言无关 - 关于utf8mb4字符集:
MySQL在5.5.3之后增加了这个utf8mb4的编码,是utf8的超集(GB18030是GBK的超集),mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。常用于存储一些UTF8三个字节无法存储的数据:包括 Emoji 表情(Emoji 是一种特殊的 Unicode 编码,常见于 ios 和 android 手机上),和很多不常用的汉字,以及任何新增的 Unicode 字符等等。一般为了节省空间使用utf8编码就已经足够了。
更多的区别可以参考:
全面了解mysql中utf8和utf8mb4的区别 - 如何选取合适的字符集:
- 满足地区语言的需求,建议使用utf8;
- 如果涉及到已有数据的导入,要充分考虑对已有数据的兼容;
- 数据库只需要支持一般中文,数据量大,性能要求也高,那么久应该选取双字节编码的GBK,而不是三字节编码的utf8;
- 如果数据库需要大量的字符运算,如排序比较等,那么选择定长字符集可能更好。
- 如果所有的客户端程序都支持相同的字符集,那么最好使用该字符集。
3)字符集、校对集的设置及修改:
MySQL的字符集和校对集有4个级别的默认设置:服务器级,数据库级,表级和字段级。
- 服务器字符集和校对集:
可以在my.conf中设置:
或者在启动选项中指定(推荐):[mysqld] character-set-server=gbk;
或者在编译时指定:mysql --character-set-sever=gbk;
校对集则会使用字符集默认的校对集。也可以手动指定。shell>cmake . -DDEFAULT_CHARSET=gbk;
查看当前字符集:
查看当前校对集:show variables like 'character_set_server';
show variables like 'collation_server';
- 数据库字符集和校对规则:
可以在创建数据库时创建:
也可以在创建后修改:CREATE DATABASE test CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
如果创建时未指定字符集和校对集,则使用服务器的字符集和校对集。Alter database dbname [库选项]; Charset/character set [=] 字符集 Collate [=] 校对集
如果只指定了字符集或者校对集其中之一,则会自动使用默认的字符集或校对集。
查看数据库的字符集(在数据库环境下使用):
查看数据库的校对集:show variables like 'character_set_database';
show variables like 'collation_database';
- 数据表的字符集和校对集:
可以在创建表的时候指定:
也可以通过修改表设置:Create table [if not exists] 表名(字段名称 数据类型,字段名称 数据类型...)ENGINE=.. CHARSET=.. COLLATE=..;
如果创建时未指定字符集和校对集,则使用数据库的字符集和校对集。Alter table 表名 表选项 [=] 值;
如果只指定了字符集或者校对集其中之一,则会自动使用默认的字符集或校对集。
显示表的字符集与校对集可以查看建表语句得知:show create table 表名;
- 字段字符集和校对规则:
一般不太使用,在建表时设置字段的字符集,修改字段时也可以设置,只是为了更加灵活,一般情况下不会用到。 - 连接字符集和校对集:
服务器和客户端之间交互的字符集和校对集的设置:
详情见:set names 字符集;
MySQL学习笔记一中关于web乱码的部分
最后更新: 2018年04月03日 13:36
原始链接: https://zjxkenshine.github.io/2018/03/27/MySQL数据库学习笔记(八)/