本篇主要内容
为什么使用视图、视图的创建、修改和删除;为什么使用存储过程,三种参数在存储过程中的使用;如何进行事务处理,以及事务隔离级别的种类及各自的缺陷。话不多说,进入正题!
视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索 数据的查询。
视图的作用:
创建视图之后,可以用与表基本相同的方式使用它们。可以对视图执行 SELECT
操作,过滤和排序数据,将视图联结到其他视图或表,甚至添加和更新数据。
用 CREATE VIEW
语句来创建视图。详细使用方式见下节。
一个最常见的视图应用是隐藏复杂的 SQL
,这通常涉及联结。
现在创建一个名为 ProductCustomers
的视图,它联结三个表,返回已订购了任意产品的所有顾客的列表。
mysql> CREATE VIEW ProductCustomers AS
-> SELECT cust_name, cust_contact, prod_id
-> FROM Customers, Orders, OrderItems
-> WHERE Customers.cust_id = Orders.cust_id
-> AND OrderItems.order_num = Orders.order_num;
通过该视图,查询订购了产品 RGAN01
的顾客。
mysql> SELECT cust_name, cust_contact
-> FROM ProductCustomers
-> WHERE prod_id = 'RGAN01';
+---------------+--------------------+
| cust_name | cust_contact |
+---------------+--------------------+
| Fun4All | Denise L. Stephens |
| The Toy Store | Kim Howard |
+---------------+--------------------+
可以看出,视图极大地简化了复杂 SQL
语句的使用。
可以定义 CustomerEMailList
视图,过滤没有电子邮件地址的顾客。
mysql> CREATE VIEW CustomerEMailList AS
-> SELECT cust_id, cust_name, cust_email
-> FROM Customers
-> WHERE cust_email IS NOT NULL;
现在,可以像使用其他表一样使用视图 CustomerEMailList
。
mysql> SELECT *
-> FROM CustomerEMailList;
+------------+--------------+-----------------------+
| cust_id | cust_name | cust_email |
+------------+--------------+-----------------------+
| 1000000001 | Village Toys | sales@villagetoys.com |
| 1000000003 | Fun4All | jjones@fun4all.com |
| 1000000004 | Fun4All | dstephens@fun4all.com |
+------------+--------------+-----------------------+
使用 ALTER VIEW
语句来修改视图,修改时要保证视图存在。
现在同样过滤没有电子邮件地址的顾客,但只返回 cust_id
列。
mysql> ALTER VIEW CustomerEMailList AS
-> SELECT cust_id
-> FROM Customers
-> WHERE cust_email IS NOT NULL;
使用 DROP VIEW
语句来删除视图,删除时要保证视图存在。
DROP VIEW CustomerEMailList;
因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索。如果你用多个联结和过滤创建了复杂的视图或者嵌 套了视图,性能可能会下降得很厉害。因此,在部署使用了 大量视图 的应用前,应该进行测试。
优点:
简单来说,使用存储过程有三个主要的好处:简单、安全、高性能。
我们来看一个简单的存储过程例子,对具有邮件地址的顾客进行计数。
mysql> DELIMITER $$
mysql> CREATE PROCEDURE MailingListCount()
-> BEGIN
-> SELECT COUNT(*) AS cust_count
-> FROM Customers
-> WHERE cust_email IS NOT NULL;
-> END$$
在定义过程时,使用 DELIMITER $$
命令将语句的结束符号从分号 ;
临时改为 $$
,使得过程体中使用的分号被直接传递到服务器,而不会被 Mysql
解释。
使用 CALL 存储过程名(参数)
来调用存储过程。
mysql> DELIMITER ;
mysql> CALL MailingListCount();
+------------+
| cust_count |
+------------+
| 3 |
+------------+
存储过程体包含了在过程调用时必须执行的语句,例如: dml、ddl
语句,if-then-else
和 while-do
语句、声明变量的declare
语句等。
过程体格式:以 begin
开始,以 end
结束(可嵌套)
BEGIN
BEGIN
BEGIN
statements;
END
END
END
注意:每个嵌套块及其中的每条语句,必须以分号结束,表示过程体结束的 begin-end
块(又叫做复合语句 compound statement
),则不需要分号。
存储过程可以有 0 个或多个参数,用于存储过程的定义。
3种参数类型:
IN
(输入参数):表示调用者向过程传入值(传入值可以是字面量或变量)OUT
(输出参数):表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)INOUT
(输入输出参数):既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)mysql> DELIMITER $$
mysql> CREATE PROCEDURE in_test(IN p_in INT)
-> BEGIN
-> SELECT p_in; -- 第一次查询
-> SET p_in = 2; -- 修改p_in的值
-> SELECT p_in; -- 第二次查询
-> END$$
mysql> DELIMITER ;
mysql> SET @p_in = 1;
mysql> CALL in_test(@p_in);
+------+
| p_in |
+------+
| 1 |
+------+
+------+
| p_in |
+------+
| 2 |
+------+
mysql> SELECT @p_in;
+-------+
| @p_in |
+-------+
| 1 |
+-------+
虽然 p_in
在存储过程中被修改,但并不影响 @p_in
的值,因为 in_test
只接受输入参数,并不输出参数,所以相当于在函数内改变,但并未将这个值输出给 @p_in
。
mysql> DELIMITER $$
mysql> CREATE PROCEDURE out_test(OUT p_out INT)
-> BEGIN
-> SELECT p_out; -- 第一次查询
-> SET p_out = 2; -- 修改p_out的值
-> SELECT p_out; -- 第二次查询
-> END$$
mysql> DELIMITER ;
mysql> SET @p_out = 1;
mysql> CALL out_test(@p_out);
+-------+
| p_out |
+-------+
| NULL |
+-------+
+-------+
| p_out |
+-------+
| 2 |
+-------+
mysql> SELECT @p_out;
+--------+
| @p_out |
+--------+
| 2 |
+--------+
第一个返回结果为 NULL
是因为 OUT
是向调用者输出参数,不接收输入的参数,所以第一次查询时 p_out
还未赋值,所以是 NULL
。最后 @p_out
变量的值变为2是因为调用了 out_test
存储过程,输出参数,改变了 p_out
变量的值。
mysql> DELIMITER $$
mysql> CREATE PROCEDURE inout_test(INOUT p_inout INT)
-> BEGIN
-> SELECT p_inout; -- 第一次查询
-> SET p_inout = 2; -- 修改p_inout的值
-> SELECT p_inout; -- 第一次查询
-> END$$
mysql> DELIMITER ;
mysql> SET @p_inout = 1;
mysql> CALL inout_test(@p_inout);
+---------+
| p_inout |
+---------+
| 1 |
+---------+
+---------+
| p_inout |
+---------+
| 2 |
+---------+
mysql> SELECT @p_inout;
+----------+
| @p_inout |
+----------+
| 2 |
+----------+
调用 inout_test
存储过程,既接受了输入的参数,也输出参数, @p_inout
的值被改变。
使用 DROP PROCEDURE
来删除存储过程。
mysql> DROP PROCEDURE in_test;
事务处理(transaction processing)是一种机制, 用来管理必须成批执行的
SQL` 操作,保证数据库不包含不完整的操作结果。利用事务处理,可以保证一组操作不会中途停止,它们要么完全执行,要么完全不执行(除非明确指示)。如果没有错误发生,整组语句提交给(写到)数据库表;如果发生错误,则进行回退(撤销),将数据库恢复到某个已知且安全的状态,以此来维护数据库的完整性。
事务处理术语:
SQL
语句;SQL
语句的过程;SQL
语句结果写入数据库表;事务处理用来管理 INSERT
、UPDATE
和 DELETE
语句。不能回退 SELECT
语句(回退 SELECT
语句也没有必要),也不能回退 CREATE
或 DROP
操 作。事务处理中可以使用这些语句,但进行回退时,这些操作也不撤销。
一般来说,事务是必须满足4个条件( ACID
)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
transaction
)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚( Rollback
)到事务开始前的状态,就像这个事务从来没有执行过一样。Read uncommitted
)、读提交( read committed
)、可重复读( repeatable read
)和串行化( Serializable
)。BEGIN / START TRANSACTION
:显式地开启一个事务;COMMIT / COMMIT WORK
:提交事务,使已对数据库进行的所有修改成为永久性的;ROLLBACK / ROLLBACK WORK
:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;SAVEPOINT
:SAVEPOINT
允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT
;RELEASE SAVEPOINT
:删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;ROLLBACK TO
:把事务回滚到标记点;SET TRANSACTION
:用来设置事务的隔离级别。InnoDB
存储引擎提供事务的隔离级别有 READ UNCOMMITTED
(读未提交)、READ COMMITTED
(读已提交,项目中常用)、REPEATABLE READ
(可重复读,Mysql
默认隔离级别) 和 SERIALIZABLE
(串行化)。简单示例:
mysql> use test;
mysql> CREATE TABLE transaction_test(id int(5)) ENGINE = INNODB; # 创建数据表
mysql> SELECT * FROM transaction_test;
Empty set (0.01 sec)
mysql> BEGIN; # 开始事务
mysql> INSERT INTO runoob_transaction_test VALUE(1);
mysql> INSERT INTO runoob_transaction_test VALUE(2);
mysql> COMMIT; # 提交事务
mysql> SELECT * FROM transaction_test;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
mysql> BEGIN; # 开始事务
mysql> INSERT INTO transaction_test VALUES(3);
mysql> SAVEPOINT first_insert; # 声明一个保存点
mysql> INSERT INTO transaction_test VALUES(4);
mysql> SAVEPOINT second_insert; # 声明一个保存点
mysql> INSERT INTO transaction_test VALUES(5);
mysql> ROLLBACK TO second_insert; # 回滚到 second_insert 保存点
mysql> SELECT * FROM transaction_test; # 因为回滚所以数据没有插入
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
+------+
mysql> ROLLBACK TO first_insert;
mysql> SELECT * FROM transaction_test;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
mysql> COMMIT; # 执行 COMMIT 或 ROLLBACK 后保存点自动释放
先看一下如何查看事务隔离级别。
# 查看默认事务隔离级别(session)
select @@transaction_isolation;
# 查看当前会话的隔离级别
select @@session.transaction_isolation;
# 查看全局的事务隔离级别
select @@global.transaction_isolation;
在 Mysql
下事务的隔离级别有四种,由低到高依次为 Read uncommitted
、Read committed
、Repeatable read
(默认)、Serializable
,这四个级别中的后三个级别可以逐个解决脏读 、不可重复读 、幻读的问题。
对于两个事务T1与T2,T1读取了已经被T2更新但是还没有提交的字段之后,若此时T2回滚,T1读取的内容就是临时并且无效的。
示例:
打开两个Mysql客户端,分别执行下面操作,查询当前会话的隔离级别(默认 REPEATABLE READ
)。修改当前会话隔离级别为( READ UNCOMMITTED
)。全局事务隔离级别仍然为 REPEATABLE READ
。
mysql> SELECT @@session.transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; # 修改会话隔离级别
mysql> SELECT @@session.transaction_isolation; # 当前会话隔离级别已修改
+---------------------------------+
| @@session.transaction_isolation |
+---------------------------------+
| READ-UNCOMMITTED |
+---------------------------------+
mysql> SELECT @@global.transaction_isolation; # 全局事务隔离级别未修改
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| REPEATABLE-READ |
+--------------------------------+
之后黑框用来做更新,白框用来查询。
|
|
| ------------ |
由于黑框的 ④ 回滚,白色背景的客户端中 ③ 读取的数据就是临时并且无效的。即脏读。
对于两个事务T1和T2,T1读取了一个字段,然后T2更新了该字段并提交之后,当T1再次读取的时候,结果不一致的情况发生。
|
|
| ------------ |
由于黑框的更新操作,白框出现两次读取的结果不一致。
对于两个事务T1、T2,T1从表中读取数据,然后T2进行了INSERT操作并提交,当T1再次读取的时候,结果不一致的情况发生。
|
|
| ------------ |
由于黑框的插入操作,白框出现两次读取的结果不一致。
几种现象在各隔离级别中出现的可能性:
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
---|---|---|---|
未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行化(Serializable ) | 不可能 | 不可能 | 不可能 |
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_43965708/article/details/117653918
内容来源于网络,如有侵权,请联系作者删除!