数据库开发——MySQL——内置功能

一、视图

视图本质上是根据SQL语句获取的动态数据集并命名存储在内存中的虚拟表。

用户使用时只需使用视图的名称即可获取其数据集并当做表来使用。

使用视图我们可以吧查询过程中的临时表存储为视图,这样以后该再想操作该临时数据表时就无需重写复杂的SQL了,直接去视图里查找即可。

但视图有明显地效率问题,并且视图是存放在数据库中的,如果程序中使用的SQL过分依赖数据库中的视图,即强耦合,那就意味着扩展SQL极为不便。

1.创建视图

语法:CREATE VIEW 视图名称 AS SQL语句

mysql> create view 201_view as select * from employee where dep_id = 201;
Query OK, 0 rows affected (0.31 sec)

mysql> select * from 201_view;
+----+---------+--------+------+--------+
| id | name    | sex    | age  | dep_id |
+----+---------+--------+------+--------+
|  3 | wupeiqi | male   |   38 |    201 |
|  8 | Coco    | female |   19 |    201 |
+----+---------+--------+------+--------+
2 rows in set (0.00 sec)

注意:

  1. 使用视图以后就无需每次都重写子查询的sql,但是这么效率并不高,还不如我们写子查询的效率高。

  2. 视图是存放到数据库里的,如果程序中的sql过分依赖于数据库中存放的视图,一旦sql需要修改且涉及到视图的部分,则必须去数据库中进行修改,而通常在公司中数据库有专门的DBA负责,极其地不方便

2.修改视图

修改视图会导致原始表中的数据也跟着改变。

mysql> update 201_view set dep_id = 200 where name = "Coco";
Query OK, 2 rows affected (0.21 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> select * from 201_view;		# 不符合视图条件的会直接被删掉
+----+---------+------+------+--------+
| id | name    | sex  | age  | dep_id |
+----+---------+------+------+--------+
|  3 | wupeiqi | male |   38 |    201 |
+----+---------+------+------+--------+
1 row in set (0.00 sec)

mysql> select * from employee;		# 原始表中的数据被修改
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  1 | egon       | male   |   18 |    200 |
|  3 | wupeiqi    | male   |   38 |    201 |
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
|  8 | Coco       | female |   19 |    200 |
|  9 | Bei        | female |    2 |    202 |
| 11 | Coco       | female |   19 |    200 |
| 12 | Bei        | female |    2 |    202 |
+----+------------+--------+------+--------+
9 rows in set (0.00 sec)

3.修改视图

语法:ALTER VIEW 视图名称 AS SQL语句

**mysql> alter view 201_view as select * from employee where dep_id = 200;
Query OK, 0 rows affected (0.46 sec)

mysql> select * from 201_view;
+----+-----------+--------+------+--------+
| id | name      | sex    | age  | dep_id |
+----+-----------+--------+------+--------+
|  1 | egon      | male   |   18 |    200 |
|  5 | liwenzhou | male   |   18 |    200 |
|  8 | Coco      | female |   19 |    200 |
| 11 | Coco      | female |   19 |    200 |
+----+-----------+--------+------+--------+
4 rows in set (0.00 sec)**

4.删除视图

语法:DROP VIEW 视图名称

二、触发器

使用触发器可以定制用户对表进行【增、删、改】操作时前后的行为,注意:没有查询。

1.创建触发器

插入触发器

# 插入前
CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 插入后
CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
BEGIN
    ...
END

删除触发器

# 删除前
CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 删除后
CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW
BEGIN
    ...
END

更新触发器

# 更新前
CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW
BEGIN
    ...
END

# 更新后
CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW
BEGIN
    ...
END

测试

创建命令表:

mysql> CREATE TABLE cmd (
    ->     id INT PRIMARY KEY auto_increment,
    ->     USER CHAR (32),
    ->     priv CHAR (10),
    ->     cmd CHAR (64),
    ->     sub_time datetime, #提交时间
    ->     success enum ('yes', 'no') #0代表执行失败
    -> );
Query OK, 0 rows affected (1.58 sec)

创建错误日志表:

mysql> CREATE TABLE errlog (
    ->     id INT PRIMARY KEY auto_increment,
    ->     err_cmd CHAR (64),
    ->     err_time datetime
    -> );
Query OK, 0 rows affected (0.66 sec)

NEW表示即将插入的数据行,OLD表示即将删除的数据行。

创建触发器:

mysql> delimiter //
mysql> CREATE TRIGGER tri_after_insert_cmd AFTER INSERT ON cmd FOR EACH ROW
    -> BEGIN
    ->     IF NEW.success = 'no' THEN #等值判断只有一个等号
    ->             INSERT INTO errlog(err_cmd, err_time) VALUES(NEW.cmd, NEW.sub_time) ; #必须加分号
    ->       END IF ; #必须加分号
    -> END//
Query OK, 0 rows affected (0.32 sec)

mysql> delimiter ;

插入数据:

mysql> INSERT INTO cmd (
    ->     USER,
    ->     priv,
    ->     cmd,
    ->     sub_time,
    ->     success
    -> )
    -> VALUES
    ->     ('Alex','0755','ls -l /etc',NOW(),'yes'),
    ->     ('Alex','0755','cat /etc/passwd',NOW(),'no'),
    ->     ('Alex','0755','useradd xxx',NOW(),'no'),
    ->     ('Alex','0755','ps aux',NOW(),'yes');
Query OK, 4 rows affected (0.71 sec)
Records: 4  Duplicates: 0  Warnings: 0

查询错误日志:

mysql> select * from errlog;
+----+-----------------+---------------------+
| id | err_cmd         | err_time            |
+----+-----------------+---------------------+
|  1 | cat /etc/passwd | 2020-02-17 17:37:38 |
|  2 | useradd xxx     | 2020-02-17 17:37:38 |
+----+-----------------+---------------------+
2 rows in set (0.06 sec)

2.删除触发器

drop trigger tri_after_insert_cmd;

三、事务

事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。

创建数据和表:

mysql> create table user(
    -> id int primary key auto_increment,
    -> name char(32),
    -> balance int
    -> );
Query OK, 0 rows affected (1.09 sec)

mysql> insert into user(name,balance)
    -> values
    -> ('wsb',1000),
    -> ('egon',1000),
    -> ('ysb',1000);
Query OK, 3 rows affected (0.14 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |    1000 |
|  2 | egon |    1000 |
|  3 | ysb  |    1000 |
+----+------+---------+
3 rows in set (0.03 sec)

正常情况:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set balance=900 where name='wsb'; #买支付100元
Query OK, 1 row affected (0.12 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set balance=1010 where name='egon'; #中介拿走10元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set balance=1090 where name='ysb'; #卖家拿到90元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.15 sec)

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |     900 |
|  2 | egon |    1010 |
|  3 | ysb  |    1090 |
+----+------+---------+
3 rows in set (0.00 sec)

出现错误的情况:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set balance=900 where name='wsb'; #买支付100元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set balance=1010 where name='egon'; #中介拿走10元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> uppdate user set balance=1090 where name='ysb'; #卖家拿到90元,出现异常没有拿到
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'uppdate user set balance=1090 where name='ysb'' at line 1
mysql> rollback;
Query OK, 0 rows affected (0.04 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |    1000 |
|  2 | egon |    1000 |
|  3 | ysb  |    1000 |
+----+------+---------+
3 rows in set (0.00 sec)

实现原理

delimiter //
create PROCEDURE p5(
    OUT p_return_code tinyint
)
BEGIN 
    DECLARE exit handler for sqlexception 
    BEGIN 
        -- ERROR 
        set p_return_code = 1; 
        rollback; 
    END; 

    DECLARE exit handler for sqlwarning 
    BEGIN 
        -- WARNING 
        set p_return_code = 2; 
        rollback; 
    END; 

    START TRANSACTION; 
        DELETE from tb1; #执行失败
        insert into blog(name,sub_time) values('yyy',now());
    COMMIT; 

    -- SUCCESS 
    set p_return_code = 0; #0代表执行成功

END //
delimiter ;

四、存储过程

存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql。

使用存储过程的优点:

1.用于替代程序写的SQL语句,实现程序与sql解耦
2.基于网络传输,传别名的数据量小,而直接传sql数据量大

使用存储过程的缺点:

1. 程序员扩展功能不方便

1.无参的存储过程

mysql> delimiter //
mysql> create procedure p1()
    -> begin
    ->  select * from employee;
    ->  insert into employee(name, sex, age, dep_id) values ("Alex", "male", 19, 200);
    -> end //
Query OK, 0 rows affected (0.42 sec)

mysql> delimiter ;

mysql> show create procedure p1;
+-----------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
| Procedure | sql_mode           | Create Procedure                                                                                                                                                      | character_set_client | collation_connection | Database Collation |
+-----------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
| p1        | ONLY_FULL_GROUP_BY | CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
begin
        select * from employee;
        insert into employee(name, sex, age, dep_id) values ("Alex", "male", 19, 200);
end | utf8                 | utf8_general_ci      | utf8_general_ci    |
+-----------+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+--------------------+
1 row in set (0.11 sec)

在MySQL中调用:

mysql> call p1();
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  1 | egon       | male   |   18 |    200 |
|  3 | wupeiqi    | male   |   38 |    201 |
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
|  8 | Coco       | female |   19 |    200 |
|  9 | Bei        | female |    2 |    202 |
| 11 | Coco       | female |   19 |    200 |
| 12 | Bei        | female |    2 |    202 |
+----+------------+--------+------+--------+
9 rows in set (0.11 sec)

Query OK, 1 row affected (0.23 sec)

mysql> select * from employee;
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  1 | egon       | male   |   18 |    200 |
|  3 | wupeiqi    | male   |   38 |    201 |
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
|  8 | Coco       | female |   19 |    200 |
|  9 | Bei        | female |    2 |    202 |
| 11 | Coco       | female |   19 |    200 |
| 12 | Bei        | female |    2 |    202 |
| 13 | Alex       | male   |   19 |    200 |
+----+------------+--------+------+--------+
10 rows in set (0.00 sec)

在python中调用:

import pymysql


conn = pymysql.connect(host="localhost", user="root", password="20001001", database="db")
cursor = conn.cursor()

cursor.callproc("p1")
print(cursor.fetchall())

输出结果为:

((1, 'egon', 'male', 18, 200), (3, 'wupeiqi', 'male', 38, 201), (4, 'yuanhao', 'female', 28, 202), (5, 'liwenzhou', 'male', 18, 200), (6, 'jingliyang', 'female', 18, 204), (8, 'Coco', 'female', 19, 200), (9, 'Bei', 'female', 2, 202), (11, 'Coco', 'female', 19, 200), (12, 'Bei', 'female', 2, 202), (13, 'Alex', 'male', 19, 200))

2.有参的存储过程

对于存储过程,可以接收参数,其参数有三类:

in          仅用于传入参数用
out        	仅用于返回值用
inout     	既可以传入又可以当作返回值
mysql> delimiter //
mysql> create procedure p2(inout n1 int)
    -> begin
    ->  select * from employee where id > n1;
    ->  set n1 = 1;
    -> end //
Query OK, 0 rows affected (0.42 sec)

mysql> delimiter ;

在MySQL中调用:

mysql> set @x = 3;
Query OK, 0 rows affected (0.00 sec)

mysql> call p2(@x);
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
|  8 | Coco       | female |   19 |    200 |
|  9 | Bei        | female |    2 |    202 |
| 11 | Coco       | female |   19 |    200 |
| 12 | Bei        | female |    2 |    202 |
| 13 | Alex       | male   |   19 |    200 |
+----+------------+--------+------+--------+
8 rows in set (0.01 sec)

Query OK, 0 rows affected (0.10 sec)

mysql> select @x;
+------+
| @x   |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

在python中调用:

import pymysql


conn = pymysql.connect(host="localhost", user="root", password="20001001", database="db")
cursor = conn.cursor()

cursor.callproc("p2", (3,))
print(cursor.fetchall())

执行结果为:

((4, 'yuanhao', 'female', 28, 202), (5, 'liwenzhou', 'male', 18, 200), (6, 'jingliyang', 'female', 18, 204), (8, 'Coco', 'female', 19, 200), (9, 'Bei', 'female', 2, 202), (11, 'Coco', 'female', 19, 200), (12, 'Bei', 'female', 2, 202), (13, 'Alex', 'male', 19, 200))

3.删除存储过程

drop procedure proc_name;
posted @ 2020-02-17 22:46  AlexKing007  阅读(98)  评论(0编辑  收藏  举报