_存储过程与函数

Posted Cisyam-shark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了_存储过程与函数相关的知识,希望对你有一定的参考价值。

第15章_存储过程与函数

🏠个人主页:shark-Gao

🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉

🎉目前状况:23届毕业生,目前在某公司实习👏👏

❤️欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬😘

🖥️个人小站 :个人博客,欢迎大家访问

配套视频参考:MySQL数据库天花板–康师傅


mysql从5.0版本开始支持存储过程和函数。存储过程和函数能够将复杂的SQL逻辑封装在一起,应用程序无须关注存储过程和函数内部复杂的SQL逻辑,而只需要简单地调用存储过程和函数即可。

1. 存储过程概述

1.1 理解

含义:存储过程的英文是 Stored Procedure。它的思想很简单,就是一组经过预先编译的 SQL 语句的封装。

执行过程:存储过程预先存储在 MySQL 服务器上,需要执行的时候,客户端只需要向服务器端发出调用存储过程的命令,服务器端就可以把预先存储好的这一系列 SQL 语句全部执行。

好处

1、简化操作,提高了sql语句的重用性,减少了开发程序员的压力
2、减少操作过程中的失误,提高效率
3、减少网络传输量(客户端不需要把所有的 SQL 语句通过网络发给服务器)
4、减少了 SQL 语句暴露在网上的风险,也提高了数据查询的安全性

和视图、函数的对比

它和视图有着同样的优点,清晰、安全,还可以减少网络传输量。不过它和视图不同,视图是虚拟表,通常不对底层数据表直接操作,而存储过程是程序化的 SQL,可以直接操作底层数据表,相比于面向集合的操作方式,能够实现一些更复杂的数据处理。

一旦存储过程被创建出来,使用它就像使用函数一样简单,我们直接通过调用存储过程名即可。相较于函数,存储过程是没有返回值的。

1.2 分类

存储过程的参数类型可以是IN、OUT和INOUT。根据这点分类如下:

1、没有参数(无参数无返回)
2、仅仅带 IN 类型(有参数无返回)
3、仅仅带 OUT 类型(无参数有返回)
4、既带 IN 又带 OUT(有参数有返回)
5、带 INOUT(有参数有返回)

注意:IN、OUT、INOUT 都可以在一个存储过程中带多个。

2. 创建存储过程

2.1 语法分析

语法:

CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...)
[characteristics ...]
BEGIN
	存储过程体

END

类似于Java中的方法:

修饰符 返回类型 方法名(参数类型 参数名,...)

	方法体;

说明:

1、参数前面的符号的意思

  • IN:当前参数为输入参数,也就是表示入参;

    存储过程只是读取这个参数的值。如果没有定义参数种类,默认就是 IN,表示输入参数。

  • OUT:当前参数为输出参数,也就是表示出参;

    执行完成之后,调用这个存储过程的客户端或者应用程序就可以读取这个参数返回的值了。

  • INOUT:当前参数既可以为输入参数,也可以为输出参数。

2、形参类型可以是 MySQL数据库中的任意类型。

3、characteristics 表示创建存储过程时指定的对存储过程的约束条件,其取值信息如下:

LANGUAGE SQL
| [NOT] DETERMINISTIC
|  CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA 
| SQL SECURITY  DEFINER | INVOKER 
| COMMENT 'string'
  • LANGUAGE SQL:说明存储过程执行体是由SQL语句组成的,当前系统支持的语言为SQL。
  • [NOT] DETERMINISTIC:指明存储过程执行的结果是否确定。DETERMINISTIC表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出。NOT DETERMINISTIC表示结果是不确定的,相同的输入可能得到不同的输出。如果没有指定任意一个值,默认为NOT DETERMINISTIC。
  • CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA :指明子程序使用SQL语句的限制。
    • CONTAINS SQL表示当前存储过程的子程序包含SQL语句,但是并不包含读写数据的SQL语句;
    • NO SQL表示当前存储过程的子程序中不包含任何SQL语句;
    • READS SQL DATA表示当前存储过程的子程序中包含读数据的SQL语句;
    • MODIFIES SQL DATA表示当前存储过程的子程序中包含写数据的SQL语句。
    • 默认情况下,系统会指定为CONTAINS SQL。
  • SQL SECURITY DEFINER | INVOKER :执行当前存储过程的权限,即指明哪些用户能够执行当前存储过程。
    • DEFINER表示只有当前存储过程的创建者或者定义者才能执行当前存储过程;
    • INVOKER表示拥有当前存储过程的访问权限的用户能够执行当前存储过程。
    • 如果没有设置相关的值,则MySQL默认指定值为DEFINER。
  • COMMENT 'string':注释信息,可以用来描述存储过程。

4、存储过程体中可以有多条 SQL 语句,如果仅仅一条SQL 语句,则可以省略 BEGIN 和 END

编写存储过程并不是一件简单的事情,可能存储过程中需要复杂的 SQL 语句。

1. BEGIN…END:BEGIN…END 中间包含了多个语句,每个语句都以(;)号为结束符。
2. DECLARE:DECLARE 用来声明变量,使用的位置在于 BEGIN…END 语句中间,而且需要在其他语句使用之前进行变量的声明。
3. SET:赋值语句,用于对变量进行赋值。
4. SELECT… INTO:把从数据表中查询的结果存放到变量中,也就是为变量赋值。

5、需要设置新的结束标记

DELIMITER 新的结束标记

因为MySQL默认的语句结束符号为分号‘;’。为了避免与存储过程中SQL语句结束符相冲突,需要使用DELIMITER改变存储过程的结束符。

比如:“DELIMITER //”语句的作用是将MySQL的结束符设置为//,并以“END //”结束存储过程。存储过程定义完毕之后再使用“DELIMITER ;”恢复默认结束符。DELIMITER也可以指定其他符号作为结束符。

当使用DELIMITER命令时,应该避免使用反斜杠(‘\\’)字符,因为反斜线是MySQL的转义字符。

示例:

DELIMITER $

CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名  参数类型,...)
[characteristics ...]
BEGIN
	sql语句1;
	sql语句2;

END $

2.2 代码举例

举例1:创建存储过程select_all_data(),查看 emps 表的所有数据

DELIMITER $

CREATE PROCEDURE select_all_data()
BEGIN
	SELECT * FROM emps;
	
END $

DELIMITER ;

举例2:创建存储过程avg_employee_salary(),返回所有员工的平均工资

DELIMITER //

CREATE PROCEDURE avg_employee_salary ()
BEGIN
	SELECT AVG(salary) AS avg_salary FROM emps;
END //

DELIMITER ;

举例3:创建存储过程show_max_salary(),用来查看“emps”表的最高薪资值。

CREATE PROCEDURE show_max_salary()
	LANGUAGE SQL
	NOT DETERMINISTIC
	CONTAINS SQL
	SQL SECURITY DEFINER
	COMMENT '查看最高薪资'
	BEGIN
		SELECT MAX(salary) FROM emps;
	END //

DELIMITER ;

举例4:创建存储过程show_min_salary(),查看“emps”表的最低薪资值。并将最低薪资通过OUT参数“ms”输出

DELIMITER //

CREATE PROCEDURE show_min_salary(OUT ms DOUBLE)
	BEGIN
		SELECT MIN(salary) INTO ms FROM emps;
	END //

DELIMITER ;

举例5:创建存储过程show_someone_salary(),查看“emps”表的某个员工的薪资,并用IN参数empname输入员工姓名。

DELIMITER //

CREATE PROCEDURE show_someone_salary(IN empname VARCHAR(20))
	BEGIN
		SELECT salary FROM emps WHERE ename = empname;
	END //

DELIMITER ;

举例6:创建存储过程show_someone_salary2(),查看“emps”表的某个员工的薪资,并用IN参数empname输入员工姓名,用OUT参数empsalary输出员工薪资。

DELIMITER //

CREATE PROCEDURE show_someone_salary2(IN empname VARCHAR(20),OUT empsalary DOUBLE)
	BEGIN
		SELECT salary INTO empsalary FROM emps WHERE ename = empname;
	END //

DELIMITER ;

举例7:创建存储过程show_mgr_name(),查询某个员工领导的姓名,并用INOUT参数“empname”输入员工姓名,输出领导的姓名。

DELIMITER //

CREATE PROCEDURE show_mgr_name(INOUT empname VARCHAR(20))
	BEGIN
		SELECT ename INTO empname FROM emps
		WHERE eid = (SELECT MID FROM emps WHERE ename=empname);
	END //

DELIMITER ;

3. 调用存储过程

3.1 调用格式

存储过程有多种调用方法。存储过程必须使用CALL语句调用,并且存储过程和数据库相关,如果要执行其他数据库中的存储过程,需要指定数据库名称,例如CALL dbname.procname。

CALL 存储过程名(实参列表)

格式:

1、调用in模式的参数:

CALL sp1('值');

2、调用out模式的参数:

SET @name;
CALL sp1(@name);
SELECT @name;

3、调用inout模式的参数:

SET @name=值;
CALL sp1(@name);
SELECT @name;

3.2 代码举例

举例1:

DELIMITER //

CREATE PROCEDURE CountProc(IN sid INT,OUT num INT)
BEGIN
	SELECT COUNT(*) INTO num FROM fruits 
	WHERE s_id = sid;
END //

DELIMITER ;

调用存储过程:

mysql> CALL CountProc (101, @num);
Query OK, 1 row affected (0.00 sec)

查看返回结果:

mysql> SELECT @num;

该存储过程返回了指定 s_id=101 的水果商提供的水果种类,返回值存储在num变量中,使用SELECT查看,返回结果为3。

**举例2:**创建存储过程,实现累加运算,计算 1+2+…+n 等于多少。具体的代码如下:

DELIMITER //
CREATE PROCEDURE `add_num`(IN n INT)
BEGIN
       DECLARE i INT;
       DECLARE sum INT;
       
       SET i = 1;
       SET sum = 0;
       WHILE i <= n DO
              SET sum = sum + i;
              SET i = i +1;
       END WHILE;
       SELECT sum;
END //
DELIMITER ;

如果你用的是 Navicat 工具,那么在编写存储过程的时候,Navicat 会自动设置 DELIMITER 为其他符号,我们不需要再进行 DELIMITER 的操作。

直接使用 CALL add_num(50);即可。这里我传入的参数为 50,也就是统计 1+2+…+50 的积累之和。

3.3 如何调试

在 MySQL 中,存储过程不像普通的编程语言(比如 VC++、Java 等)那样有专门的集成开发环境。因此,你可以通过 SELECT 语句,把程序执行的中间结果查询出来,来调试一个 SQL 语句的正确性。调试成功之后,把 SELECT 语句后移到下一个 SQL 语句之后,再调试下一个 SQL 语句。这样逐步推进,就可以完成对存储过程中所有操作的调试了。当然,你也可以把存储过程中的 SQL 语句复制出来,逐段单独调试。

4. 存储函数的使用

前面学习了很多函数,使用这些函数可以对数据进行的各种处理操作,极大地提高用户对数据库的管理效率。MySQL支持自定义函数,定义好之后,调用方式与调用MySQL预定义的系统函数一样。

4.1 语法分析

学过的函数:LENGTH、SUBSTR、CONCAT等

语法格式:

CREATE FUNCTION 函数名(参数名 参数类型,...) 
RETURNS 返回值类型
[characteristics ...]
BEGIN
	函数体   #函数体中肯定有 RETURN 语句

END

说明:

1、参数列表:指定参数为IN、OUT或INOUT只对PROCEDURE是合法的,FUNCTION中总是默认为IN参数。

2、RETURNS type 语句表示函数返回数据的类型;

RETURNS子句只能对FUNCTION做指定,对函数而言这是强制的。它用来指定函数的返回类型,而且函数体必须包含一个RETURN value语句。

3、characteristic 创建函数时指定的对函数的约束。取值与创建存储过程时相同,这里不再赘述。

4、函数体也可以用BEGIN…END来表示SQL代码的开始和结束。如果函数体只有一条语句,也可以省略BEGIN…END。

4.2 调用存储函数

在MySQL中,存储函数的使用方法与MySQL内部函数的使用方法是一样的。换言之,用户自己定义的存储函数与MySQL内部函数是一个性质的。区别在于,存储函数是用户自己定义的,而内部函数是MySQL的开发者定义的。

SELECT 函数名(实参列表)

4.3 代码举例

举例1:

创建存储函数,名称为email_by_name(),参数定义为空,该函数查询Abel的email,并返回,数据类型为字符串型。

DELIMITER //

CREATE FUNCTION email_by_name()
RETURNS VARCHAR(25)
DETERMINISTIC
CONTAINS SQL
BEGIN
	RETURN (SELECT email FROM employees WHERE last_name = 'Abel');
END //

DELIMITER ;

调用:

SELECT email_by_name();

举例2:

创建存储函数,名称为email_by_id(),参数传入emp_id,该函数查询emp_id的email,并返回,数据类型为字符串型。

DELIMITER //

CREATE FUNCTION email_by_id(emp_id INT)
RETURNS VARCHAR(25)
DETERMINISTIC
CONTAINS SQL
BEGIN
	RETURN (SELECT email FROM employees WHERE employee_id = emp_id);
END //

DELIMITER ;

调用:

SET @emp_id = 102;
SELECT email_by_id(102);

举例3:

创建存储函数count_by_id(),参数传入dept_id,该函数查询dept_id部门的员工人数,并返回,数据类型为整型。

DELIMITER //

CREATE FUNCTION count_by_id(dept_id INT)
RETURNS INT
	LANGUAGE SQL
	NOT DETERMINISTIC
	READS SQL DATA
	SQL SECURITY DEFINER
	COMMENT '查询部门平均工资'
BEGIN
	RETURN (SELECT COUNT(*) FROM employees WHERE department_id = dept_id);
	
END //

DELIMITER ;

调用:

SET @dept_id = 50;
SELECT count_by_id(@dept_id);

注意:

若在创建存储函数中报错“you might want to use the less safe log_bin_trust_function_creators variable”,有两种处理方法:

  • 方式1:加上必要的函数特性“[NOT] DETERMINISTIC”和“CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA”

  • 方式2:

mysql> SET GLOBAL log_bin_trust_function_creators = 1;

4.4 对比存储函数和存储过程

关键字调用语法返回值应用场景
存储过程PROCEDURECALL 存储过程()理解为有0个或多个一般用于更新
存储函数FUNCTIONSELECT 函数()只能是一个一般用于查询结果为一个值并返回时

此外,存储函数可以放在查询语句中使用,存储过程不行。反之,存储过程的功能更加强大,包括能够执行对表的操作(比如创建表,删除表等)和事务操作,这些功能是存储函数不具备的。

5. 存储过程和函数的查看、修改、删除

5.1 查看

创建完之后,怎么知道我们创建的存储过程、存储函数是否成功了呢?

MySQL存储了存储过程和函数的状态信息,用户可以使用SHOW STATUS语句或SHOW CREATE语句来查看,也可直接从系统的information_schema数据库中查询。这里介绍3种方法。

1. 使用SHOW CREATE语句查看存储过程和函数的创建信息

基本语法结构如下:

SHOW CREATE PROCEDURE | FUNCTION 存储过程名或函数名

举例:

SHOW CREATE FUNCTION test_db.CountProc \\G

2. 使用SHOW STATUS语句查看存储过程和函数的状态信息

基本语法结构如下:

SHOW PROCEDURE | FUNCTION STATUS [LIKE 'pattern']

这个语句返回子程序的特征,如数据库、名字、类型、创建者及创建和修改日期。

[LIKE ‘pattern’]:匹配存储过程或函数的名称,可以省略。当省略不写时,会列出MySQL数据库中存在的所有存储过程或函数的信息。
举例:SHOW STATUS语句示例,代码如下:

mysql> SHOW PROCEDURE STATUS LIKE 'SELECT%' \\G 
*************************** 1. row ***************************
                  Db: test_db
                Name: SelectAllData
                Type: PROCEDURE
             Definer: root@localhost
            Modified: 2021-10-16 15:55:07
             Created: 2021-10-16 15:55:07
       Security_type: DEFINER
             Comment: 
character_set_client: utf8mb4
collation_connection: utf8mb4_general_ci
  Database Collation: utf8mb4_general_ci
1 row in set (0.00 sec)

3. 从information_schema.Routines表中查看存储过程和函数的信息

MySQL中存储过程和函数的信息存储在information_schema数据库下的Routines表中。可以通过查询该表的记录来查询存储过程和函数的信息。其基本语法形式如下:

SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='存储过程或函数的名' [AND ROUTINE_TYPE = 'PROCEDURE|FUNCTION'];

说明:如果在MySQL数据库中存在存储过程和函数名称相同的情况,最好指定ROUTINE_TYPE查询条件来指明查询的是存储过程还是函数。

举例:从Routines表中查询名称为CountProc的存储函数的信息,代码如下:

SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='count_by_id' AND ROUTINE_TYPE = 'FUNCTION' \\G

5.2 修改

修改存储过程或函数,不影响存储过程或函数功能,只是修改相关特性。使用ALTER语句实现。

ALTER PROCEDURE | FUNCTION 存储过程或函数的名 [characteristic ...]

其中,characteristic指定存储过程或函数的特性,其取值信息与创建存储过程、函数时的取值信息略有不同。

 CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA 
| SQL SECURITY  DEFINER | INVOKER 
| COMMENT 'string'
  • CONTAINS SQL,表示子程序包含SQL语句,但不包含读或写数据的语句。
  • NO SQL,表示子程序中不包含SQL语句。
  • READS SQL DATA,表示子程序中包含读数据的语句。
  • MODIFIES SQL DATA,表示子程序中包含写数据的语句。
  • SQL SECURITY DEFINER | INVOKER ,指明谁有权限来执行。
    • DEFINER,表示只有定义者自己才能够执行。
    • INVOKER,表示调用者可以执行。
  • COMMENT 'string',表示注释信息。

修改存储过程使用ALTER PROCEDURE语句,修改存储函数使用ALTER FUNCTION语句。但是,这两个语句的结构是一样的,语句中的所有参数也是一样的。

举例1:

修改存储过程CountProc的定义。将读写权限改为MODIFIES SQL DATA,并指明调用者可以执行,代码如下:

ALTER PROCEDURE CountProc
MODIFIES SQL DATA
SQL SECURITY INVOKER ;

查询修改后的信息:

SELECT specific_name,sql_data_access,security_type
FROM information_schema.`ROUTINES`
WHERE routine_name = 'CountProc' AND routine_type = 'PROCEDURE';

结果显示,存储过程修改成功。从查询的结果可以看出,访问数据的权限(SQL_DATA_ ACCESS)已经变成MODIFIES SQL DATA,安全类型(SECURITY_TYPE)已经变成INVOKER。

举例2:

修改存储函数CountProc的定义。将读写权限改为READS SQL DATA,并加上注释信息“FIND NAME”,代码如下:

ALTER FUNCTION CountProc
READS SQL DATA
COMMENT 'FIND NAME' ;

存储函数修改成功。从查询的结果可以看出,访问数据的权限(SQL_DATA_ACCESS)已经变成READS SQL DATA,函数注释(ROUTINE_COMMENT)已经变成FIND NAME。

5.3 删除

删除存储过程和函数,可以使用DROP语句,其语法结构如下:

DROP PROCEDURE | FUNCTION [IF EXISTS] 存储过程或函数的名

IF EXISTS:如果程序或函数不存储,它可以防止发生错误,产生一个用SHOW WARNINGS查看的警告。

举例:

DROP PROCEDURE CountProc;
DROP FUNCTION CountProc;

6. 关于存储过程使用的争议

尽管存储过程有诸多优点,但是对于存储过程的使用,一直都存在着很多争议,比如有些公司对于大型项目要求使用存储过程,而有些公司在手册中明确禁止使用存储过程,为什么这些公司对存储过程的使用需求差别这么大呢?

6.1 优点

**1、存储过程可以一次编译多次使用。**存储过程只在创建时进行编译,之后的使用都不需要重新编译,这就提升了 SQL 的执行效率。

**2、可以减少开发工作量。**将代码封装成模块,实际上是编程的核心思想之一,这样可以把复杂的问题拆解成不同的模块,然后模块之间可以重复使用,在减少开发工作量的同时,还能保证代码的结构清晰。

**3、存储过程的安全性强。**我们在设定存储过程的时候可以设置对用户的使用权限,这样就和视图一样具有较强的安全性。

**4、可以减少网络传输量。**因为代码封装到存储过程中,每次使用只需要调用存储过程即可,这样就减少了网络传输量。

**5、良好的封装性。**在进行相对复杂的数据库操作时,原本需要使用一条一条的 SQL 语句,可能要连接多次数据库才能完成的操作,现在变成了一次存储过程,只需要连接一次即可

6.2 缺点

基于上面这些优点,不少大公司都要求大型项目使用存储过程,比如微软、IBM 等公司。但是国内的阿里并不推荐开发人员使用存储过程,这是为什么呢?

阿里开发规范

【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

存储过程虽然有诸如上面的好处,但缺点也是很明显的。

**1、可移植性差。**存储过程不能跨数据库移植,比如在 MySQL、Oracle 和 SQL Server 里编写的存储过程,在换成其他数据库时都需要重新编写。

**2、调试困难。**只有少数 DBMS 支持存储过程的调试。对于复杂的存储过程来说,开发和维护都不容易。虽然也有一些第三方工具可以对存储过程进行调试,但要收费。

**3、存储过程的版本管理很困难。**比如数据表索引发生变化了,可能会导致存储过程失效。我们在开发软件的时候往往需要进行版本管理,但是存储过程本身没有版本控制,版本迭代更新的时候很麻烦。

**4、它不适合高并发的场景。**高并发的场景需要减少数据库的压力,有时数据库会采用分库分表的方式,而且对可扩展性要求很高,在这种情况下,存储过程会变得难以维护,增加数据库的压力,显然就不适用了。

小结:

存储过程既方便,又有局限性。尽管不同的公司对存储过程的态度不一,但是对于我们开发人员来说,不论怎样,掌握存储过程都是必备的技能之一。

MySQL数据库_用户操作与权限管理视图存储过程触发器基本函数

用户操作与权限管理

MySQL用户操作

创建用户

方法一: CREATE USER语句创建
        CREATE USER "用户名"@"IP地址" IDENTIFIED BY "密码";

方法二: INSERT语句创建
        INSERT INTO mysql.user(user,host, password,ssl_cipher,x509_issuer,x509_subject)
        VALUES(‘用户名’,’IP地址’,password(‘密码’),’’,’’,’’);
        FLUSH PRIVILEGES;

方法三: GRANT语句创建
        GRANT SELECT ON *.* TO 用户名@’IP地址’ IDENTIFIED BY ‘密码’;
        FLUSH PRIVILEGES;

删除用户

方法一:DROP USER语句删除

       DROP USER "用户名"@"IP地址";

方法二:DELETE语句删除

       DELETE FROM mysql.user 
            WHERE user=’用户名’ AND host=’IP地址’;
       FLUSH PRIVILEGES;

修改密码

root用户修改自己密码:

方法一:
    # mysqladmin -uroot -p123 password \'new_password\'    //123为旧密码

方法二:
    UPDATE mysql.user SET password=password(‘new_password’)
           WHERE user=’root’ AND host=’localhost’;
    FLUSH PRIVILEGES;

方法三:
    SET PASSWORD=password(‘new_password’);
    FLUSH PRIVILEGES;

root修改其他用户密码:

方法一:
    SET PASSWORD FOR 用户名@’IP地址’=password(‘new_password’);
    FLUSH PRIVILEGES;

方法二:
    UPDATE mysql.user SET password=password(‘new_password’)
        WHERE user=’用户名’ AND host=’IP地址’;
    FLUSH PRIVILEGES;

方法三:
    GRANT SELECT ON *.* TO user3@’localhost’ IDENTIFIED BY ‘yuan’; 
    FLUSH PRIVILEGES;

普通用户修改自己密码:

SET password=password(‘new_password’);

丢失root用户密码:

    # vim /etc/my.cnf
    skip-grant-tables
    # service mysqld restart
    # mysql -uroot
    mysql> UPDATE mysql.user SET password=password(‘new_password’)
    WHERE user=’root’ AND host=’localhost’;
    mysql> FLUSH PRIVILEGES;   

修改用户名:

rename user \'用户名\'@\'IP地址\' to \'新用户名\'@\'IP地址\';

注解 flush privileges:

/*
flush privileges 命令本质上的作用是将当前user和privilige表中的用户信息/权限设置从mysql库(MySQL数据库的内置库)中提取到内存里。
MySQL用户数据和权限有修改后,搜索希望在"不重启MySQL服务"的情况下直接生效,那么就需要执行这个命令
*/

添加远程访问

GRANT ALL PRIVILEGES ON *.* TO ruser@localhost IDENTIFIED BY \'123456\' WITH GRANT OPTION; 
GRANT ALL PRIVILEGES ON *.* TO ruser@\'%\' IDENTIFIED BY \'123456\' WITH GRANT OPTION; 

  

 

MySQL权限管理

授权

--语法格式:
grant 权限列表 on 库名.表名 to 用户名@\'客户端主机\' [identified by \'密码\' with option参数];

示例

-- 给该用户授予对数据库db1下的表tb1所有的操作权限
grant all privileges on db1.tb1 TO \'用户名\'@\'IP\'  

-- 给该用户授予对数据库db1下所有表进行查操作的权限
grant select on db1.* TO \'用户名\'@\'IP\'   
  
-- 给该用户授予对所有数据库下所有表进行查和增的操作     
grant select,insert on *.* TO \'用户名\'@\'IP\'   
    
-- 用户只能在该IP段下才能(通配符%表示任意)对所有数据库下所有表进行查操作
grant select on *.* TO \'用户名\'@\'192.168.1.%\'     
  
-- 用户能用户可以在任意IP下(通配符%表示任意)对所有数据库下所有表进行查操作    
grant select on *.* TO \'用户名\'@\'%\'   
View Code

with_option参数:

GRANT OPTION-- 授权选项


    MAX_QUERIES_PER_HOUR:                        -- 定义每小时允许执行的查询数
    MAX_UPDATES_PER_HOUR:                        -- 定义每小时允许执行的更新数
    MAX_CONNECTIONS_PER_HOUR:                    -- 定义每小时可以建立的连接数
    MAX_USER_CONNECTIONS:                        -- 定义单个用户同时可以建立的连接数
View Code

示例: 限制用户每小时的查询数量

mysql> grant select on *.* to \'用户名\'@\'IP地址\' identified by \'123456\' with max_queries_per_hour 5;

查看权限

show grants for \'用户\'@\'IP地址\'

回收权限

--语法:
    REVOKE 权限列表 ON 库名.表名 FROM 用户名@‘客户端主机’

示例:

 REVOKE DELETE ON *.*  FROM 用户名@’%’;             -- 回收部分权限
 REVOKE ALL PRIVILEGES FROM 用户名@’%’;             -- 回收所有权限

视图

1.为什么使用视图

    为了提高复杂SQL语句的复用性和表操作的安全性(例如:工资字段不想展示给所有能查看该查询结果的人),MySQL提供了视图特性。所谓视图,本质上是一种虚拟表,其内容与真实的表相似,包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储数据值的形式存在。行和列的数据来自定义视图的查询所引用基本表,并且在具体使用视图时动态生成。 
视图有如下特点;
      1. 视图的列可以来自不同的表,是表的抽象和逻辑意义上建立的新关系。
      2. 视图是由基本表(实表)产生的表(虚表)。
      3. 视图的建立和删除不影响基本表。
      4. 对视图内容的更新(添加、删除和修改)直接影响基本表。
      5. 当视图来自多个基本表时,不允许添加和删除数据。

2.创建视图

在创建视图时,首先要确保拥有CREATE VIEW的权限,并且同时确保对创建视图所引用的表也具有相应的权限。 
2.1 创建视图的语法形式: 
    虽然视图可以被看成是一种虚拟表,但是其在物理上是不存在的,即数据库管理系统没有专门的位置为视图存储数据。根据视图的概念发现其数据来源于查询语句,因此创建视图的语法为:

CREATE VIEW view_name AS 查询语句
//说明:和创建表一样,视图名不能和表名、也不能和其他视图名重名。视图的功能实际就是封装了复杂的查询语句。

示例:

use view_test;  //选择一个自己创建的库
create table t_product( //创建表
  id int primary key,
  pname varchar(20),
  price decimal(8,2)
); 
insert into t_product values(1,\'apple\',6.5); //向表中插入数据
insert into t_product values(2,\'orange\',3); //向表中插入数据
create view view_product as select id,pname from t_product; //创建视图
select * from view_product;

结果为:



//其实在创建视图时实际代码里写的是一个表查询语句,只不过把这个查询语句封装起来重新起了一个名字,方便可以重复使用。
//再者,安全性方面可以隐藏一些不希望看到的字段,比如这里的价格字段。
//注意:在SQL语句的命名规范中,视图一般以view_xxx或者v_xxx的样式来命名。视图的查询语句和表的查询语句相同。

2.2 创建各种视图: 
    由于视图的功能实际上时封装查询语句,那么是不是任何形式的查询语句都可以封装在视图中呢? 

封装使用聚合函数(SUM、MIN、MAX、COUNT等)查询语句的视图: 示例:
首先准备需要用到的两张表及其初始化数据;

CREATE TABLE t_group(
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20)
);
CREATE TABLE t_student(
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20),
  sex CHAR(1),
  group_id INT,
  FOREIGN KEY (group_id) REFERENCES t_group (id)
);
//t_group表中插入数据
INSERT INTO t_group (NAME) VALUES(\'group_1\');
INSERT INTO t_group (NAME) VALUES(\'group_2\');
INSERT INTO t_group (NAME) VALUES(\'group_3\');
INSERT INTO t_group (NAME) VALUES(\'group_4\');
INSERT INTO t_group (NAME) VALUES(\'group_5\');
//t_student表中插入数据
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_1\',\'M\',1);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_2\',\'M\',1);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_3\',\'M\',2);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_4\',\'W\',2);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_5\',\'W\',2);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_6\',\'W\',2);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_7\',\'M\',3);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_8\',\'W\',4);
INSERT INTO t_student (NAME,sex,group_id) VALUES(\'yuan_9\',\'W\',4);
================================================================
mysql> create view view_test2 as select count(name) from t_student;
Query OK, 0 rows affected (0.71 sec)
mysql> select * from view_test2;
+-------------+
| count(name) |
+-------------+
|      9      |
+-------------+
1 row in set (0.01 sec)

2.2.3 封装了实现排序功能(ORDER BY)查询语句的视图:

示例:

mysql> create view view_test3 as select name from t_student order by id desc;
Query OK, 0 rows affected (0.06 sec)
mysql> select * from view_test3;
+--------+
| name   |
+--------+
| yuan_9 |
| yuan_8 |
| yuan_7 |
| yuan_6 |
| yuan_5 |
| yuan_4 |
| yuan_3 |
| yuan_2 |
| yuan_1 |
+--------+ 9 rows in set (0.00 sec)

2.2.4 封装了实现表内连接查询语句的视图:

示例:(第二组学生的姓名)

mysql> create view view_test5 as select s.name from t_student s,t_group g where s.group_id=g.id and g.id=2;
Query OK, 0 rows affected (0.07 sec)
mysql> select * from view_test5;
+--------+
| name   |
+--------+
| yuan_3 |
| yuan_4 |
| yuan_5 |
| yuan_6 |
+-------+
4 rows in set (0.00 sec)

2.2.6 封装了实现子查询相关查询语句的视图:

示例:

mysql> create view view_test7 as select s.name from t_student s where s.id in(select id from t_group);
Query OK, 0 rows affected (0.08 sec)
mysql> select * from view_test7;
+--------+
| name   |
+--------+
| yuan_1 |
| yuan_2 |
| yuan_3 |
| yuan_4 |
| yuan_5 |
+--------+ 5 rows in set (0.00 sec)

2.2.7 封装了实现记录联合(UNION和UNION ALL)查询语句的视图:

mysql> create view view_test8 as select id,name from t_student union all select id,name from t_group;
Query OK, 0 rows affected (0.08 sec)
mysql> select * from view_test8;
+----+---------+
| id | name    |
+----+---------+
|  1 | yuan_1  |
|  2 | yuan_2  |
|  3 | yuan_3  |
|  4 | yuan_4  |
|  5 | yuan_5  |
|  6 | yuan_6  |
|  7 | yuan_7  |
|  8 | yuan_8  |
|  9 | yuan_9  |
|  1 | group_1 |
|  2 | group_2 |
|  3 | group_3 |
|  4 | group_4 |
|  5 | group_5 |
+----+---------+ 14 rows in set (0.01 sec)

3.查看视图

3.1 SHOW TABLES语句查看视图名: 
执行SHOW TABLES 语句时不仅可以显示表的名字,同时也是显示出视图的名字。

示例:

mysql> show tables;
+-----------------+
| Tables_in_test2 |
+-----------------+
| goods           |
| order           |
| orders          |
| person          |
| t_group         |
| t_product       |
| t_student       |
| view_product    |
| view_test2      |
| view_test3      |
| view_test5      |
| view_test7      |
| view_test8      |
+-----------------+
13 rows in set (0.00 sec

 3.2 SHOW TABLE STATUS语句查看视图详细信息: 

和SHOW TABLES语句一样,SHOW TABLE STATUS语句不仅会显示表的详细信息,同时也会显示视图的详细信息。

语法如下:
SHOW TABLE STATUS [FROM db_name] [LIKE \'pattern\']
//参数db_name用来设置数据库,SHOW TABLES STATUS表示将显示所设置库的表和视图的详细信息。
//设置LIKE关键字,可以查看某一个具体表或视图的详细信息。例如: SHOW TABLE STATUS FROM zhaojd LIKE \'t_group\' \\G

3.3 SHOW CREATE VIEW语句查看视图定义信息:

语法为:
 SHOW CREATE VIEW viewname;

3.4 DESCRIBE | DESC 语句查看视图定义信息:

语法为:
 DESCRIBE | DESC viewname;

3.5 通过系统表查看视图信息: 
当MySQL安装成功后,会自动创建系统数据库infomation_schema。在该数据库中存在一个包含视图信息的表格,可以通过查看表格views来查看所有视图的相关信息。

示例:

mysql> use information_schema;
Database changed

mysql> select * from views where table_name=\'view_test7\' \\G;
*************************** 1. row ***************************
       TABLE_CATALOG: def
        TABLE_SCHEMA: test2
          TABLE_NAME: view_test7
     VIEW_DEFINITION: select `s`.`NAME` AS `name` from `test2`.`t_student` `s`
            where `s`.`id` in (select `test2`.`t_group`.`id` from `test2`.`t_group`)
        CHECK_OPTION: NONE
        IS_UPDATABLE: YES
             DEFINER: root@localhost
       SECURITY_TYPE: DEFINER
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
1 row in set (0.00 sec)

4.删除视图

在删除视图时首先要确保拥有删除视图的权限。

语法为:
DROP VIEW view_name [,view_name] ......
//从语法可以看出,DROP VIEW一次可以删除多个视图
示例:


mysql> drop view view_test1,view_test2;
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;

5.修改视图

5.1 CREATE OR REPLACE VIEW语句修改视图: 
对于已经创建好的表,尤其是已经有大量数据的表,通过先删除,然后再按照新的表定义重新建表的方式来修改表,需要做很多额外的工作,例如数据的重载等。可是对于视图来说,由于是“虚表”,并没有存储数据,所以完全可以通过该方式来修改视图。

实现思路就是:先删除同名的视图,然后再根据新的需求创建新的视图即可。

DROP VIEW view_name; 
CREATE VIEW view_name as 查询语句;

但是如果每次修改视图,都是先删除视图,然后再次创建一个同名的视图,则显得非常麻烦。于是MySQL提供了更方便的实现替换的创建视图的语法,完整语法为:

CREATE OR REPLACE VIEW view_name as 查询语句;

 5.2 ALTER语句修改视图:

语法为:

ALTER VIEW view_name as 查询语句;

6.利用视图操作基本表

再MySQL中可以通常视图检索基本表数据,这是视图最基本的应用,除此之后还可以通过视图修改基本表中的数据。 
6.1检索(查询)数据: 
    通过视图查询数据,与通过表进行查询完全相同,只不过通过视图查询表更安全,更简单实用。只需要把表名换成视图名即可。 
6.2利用视图操作基本表数据: 
    由于视图是“虚表”,所以对视图数据进行的更新操作,实际上是对其基本表数据进行的更新操作。在具体更新视图数据时,需要注意以下两点;
    1. 对视图数据进行添加、删除直接影响基本表。
    2. 视图来自于多个基本表时,不允许添加、删除数据。
    视图中的添加数据操作、删除数据操作、更新数据操作的语法同表完全相同。只是将表名换成视图名即可。

存储过程

我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。

一、存储过程

  存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户
通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。而我们常用的操作数据库语言SQL语句在执行的时
候需要要先编译,然后执行,所以执行的效率没有存储过程高。

  存储过程优点如下:

重复使用。存储过程可以重复使用,从而可以减少数据库开发人员的工作量。提高性能。存储过程在创建的时候在进行了编译,将来使用的时候不再重新翻译。一般的SQL语句每执行一次就需要编译一次,所以使用存储过程提高了效率。减少网络流量。存储过程位于服务器上,调用的时候只需要传递存储过程的名称以及参数就可以了,因此降低了网络传输的数据量。安全性。参数化的存储过程可以防止SQL注入式攻击,而且可以将Grant、Deny以及Revoke权限应用于存储过程。

  存储过程简单语法:

CREATE PROCEDURE 存储过程名称(
   输入输出类型 变量名称 类型,
...   )
BEGIN   -- 声明, 语句要完成的操作,增删改查。。。 END

二、参数介绍示例

  表结构如下:

-- 创建表
DROP TABLE IF EXISTS person;
CREATE TABLE person (
  `id` int(11) AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

 -- 插入数据
 INSERT person VALUES    (1,"yuan",23,123),
                         (2,"egon",33,456),
                         (3,"alex",35,789)

1、无参数存储

DELIMITER !

DROP PROCEDURE IF EXISTS proc_no_para; 

-- 创建存储过程
CREATE PROCEDURE proc_no_para()
BEGIN 
     SELECT * FROM person;
END!

DELIMITER ;


CALL proc_no_para();
View Code

2、只带IN(输入参数)的存储过程

   表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值。

DROP PROCEDURE IF EXISTS proc_person_findById;

-- 创建存储过程
 CREATE PROCEDURE proc_person_findById(
   in n int
)
BEGIN
     SELECT * FROM person where id=n;
END;

-- 定义变量
SET @n=2;
-- 调用存储过程
CALL proc_person_findById(@n);
View Code

3、只带OUT(输出参数)的存储过程

  该值可在存储过程内部被改变,并可返回。

DELIMITER !

CREATE PROCEDURE Procdure_out(
  OUT n INT(11)
)

BEGIN
    SELECT COUNT(*) INTO n FROM person;
END!

DELIMITER ;

CALL Procdure_out(@n);

SELECT @n AS "总数";
View Code

4、带IN(输入参数)和OUT(输出参数),调用时指定,并且可被改变和返回

DELIMITER !

DROP PROCEDURE IF EXISTS proc_person_findInfoById; 

-- 创建存储过程
CREATE PROCEDURE proc_person_findInfoById(
    IN n INT(11), 
    OUT pusername VARCHAR(255), 
    OUT page INT(11)
)
BEGIN 
     SELECT username, age INTO pusername, page FROM person WHERE id=n;
END!

DELIMITER ;

-- 定义变量
SET @id=1;
-- 调用存储过程
CALL proc_person_findInfoById(@id,@username, @age);
SE

以上是关于_存储过程与函数的主要内容,如果未能解决你的问题,请参考以下文章

MySQL数据库_用户操作与权限管理视图存储过程触发器基本函数

mysql 存储过程与存储函数

mysql 存储过程入门

MySQL数据库之存储过程与存储函数

MySQL数据库函数与MySQL数据库存储过程!

MySQL数据库函数与MySQL数据库存储过程!