Mysql数据库(3)

1 视图

  • 定义:是一种虚拟存在的数据表,这个虚拟的表并不在数据库中实际存在。
  • 作用:将一些比较复杂的查询语句的结果,封装到一个虚拟表中。后期再有相同复杂查询时,直接查询这张虚拟表即可
  • 总结:视图就是将一条SELECT查询语句的结果封装到了一个虚拟表中,所以我们在创建视图的时候,工作重心就要放在这条SELECT查询语句上

(1)视图的好处

  • 简单
    • 对于使用视图的用户不需要关心表的结构、关联条件和筛选条件。因为这张虚拟表中保存的就是已经过滤好条件的结果集
  • 安全
    • 视图可以设置权限 , 致使访问视图的用户只能访问他们被允许查询的结果集
  • 数据独立
    • 一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响

(2)视图的创建

 

-- 创建db7数据库
CREATE DATABASE db7;

-- 使用db7数据库
USE db7;

-- 创建country表
CREATE TABLE country(
        id INT PRIMARY KEY AUTO_INCREMENT,
        country_name VARCHAR(30)
);
-- 添加数据
INSERT INTO country VALUES (NULL,'中国'),(NULL,'美国'),(NULL,'俄罗斯');

-- 创建city表
CREATE TABLE city(
        id INT PRIMARY KEY AUTO_INCREMENT,
        city_name VARCHAR(30),
        cid INT, -- 外键列。关联country表的主键列id
        CONSTRAINT cc_fk1 FOREIGN KEY (cid) REFERENCES country(id)
);
-- 添加数据
INSERT INTO city VALUES (NULL,'北京',1),(NULL,'上海',1),(NULL,'纽约',2),(NULL,'莫斯科',3);

-- 创建一个视图。将查询出来的结果保存到这张虚拟表中
CREATE
VIEW
        city_country
AS SELECT                     --普通的多表查询(若报错,就安排安排,各单词的间距)
        t1.*,
        t2.country_name 
        FROM 
        city t1,country t2 
        WHERE 
        t1.cid=t2.id;
        
--创建视图并指定列名基本演示
CREATE
VIEW
        city_country2 (city_id,city_name,cid,country_name) 
AS
        SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;

(3)视 图 的 查 询

SELECT * FROM city_country2; --查询视图内容(和点进去看,是一样的)
SHOW CREATE VIEW city_country; --查询视图的一些基本创建的语法,或一些结构
SHOW TABLES;   -- 查询所有数据表,视图也会查询出来

 (4)视图的修改

-- 修改视图表中的城市名称北京为北京市
UPDATE city_country SET city_name='北京市' WHERE city_name='北京';

-- 查询视图
SELECT * FROM city_country;

-- 查询city表,北京也修改为了北京市
SELECT * FROM city;

-- 注意:视图表数据修改,会自动修改源表中的数据
-- 修改视图2的列名city_id为id(和创建视图的语法是一样的)
ALTER
VIEW
        city_country2 (id,city_name,cid,country_name)
AS
        SELECT t1.*,t2.country_name FROM city t1,country t2 WHERE t1.cid=t2.id;

(5)视图的删除

-- 删除视图
DROP VIEW city_country;

-- 删除视图2,如果存在则删除
DROP VIEW IF EXISTS city_country2;

2 MySQL存储过程和函数

存储过程和函数的概念

  • 存储过程和函数是 事先经过编译并存储在数据库中的一段 SQL 语句的集合

存储过程和函数的好处(安全,高效,复用性强)

  1. 存储过程和函数可以重复使用,减轻开发人员的工作量。类似于java中方法可以多次调用
  2. 减少网络流量,存储过程和函数位于服务器上,调用的时候只需要传递名称和参数即可
  3. 减少数据在数据库和应用服务器之间的传输,可以提高数据处理的效率
  4. 将一些业务逻辑在数据库层面来实现,可以减少代码层面的业务处理

存储过程和函数的区别

函数必须有返回值,存储过程没有返回值

delimiter介绍

 (1)创建存储过程

创 建 存 储 过 程
DELIMITER $

CREATE PROCEDURE 存储过程名称(参数...)
BEGIN
        sql语句;
END$

DELIMITER ;

调 用 存 储 过 程
CALL 存储过程名称(实际参数);

查 看 存 储 过 程(了解)
SELECT * FROM mysql.proc WHERE db='数据库名称';

删 除 存 储 过 程
DROP PROCEDURE [IF EXISTS] 存储过程名称;
CREATE DATABASE db8;
USE db8;

CREATE TABLE student( 
        id INT PRIMARY KEY AUTO_INCREMENT,         -- 学生id
        NAME VARCHAR(20),                          -- 学生姓名
        age INT,                                   -- 学生年龄
        gender VARCHAR(5),                          -- 学生性别
        score INT                                   -- 学生成绩
);

INSERT INTO student VALUES (NULL,'张三',23,'男',95),(NULL,'李四',24,'男',98),
(NULL,'王五',25,'女',100),(NULL,'赵六',26,'女',90);

DELIMITER $

-- 创建存储过程,封装分组查询学生总成绩的sql语句
CREATE PROCEDURE stu_group()
BEGIN
        -- 按照性别进行分组,查询每组学生的总成绩。按照总成绩的升序排序
SELECT gender,SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;

END$
DELIMITER ;

-- 调用stu_group存储过程
CALL stu_group();

-- 删除stu_group存储过程
DROP PROCEDURE stu_group;

(2)存储过程语法(重点)

介绍:存储过程是可以进行编程的。意味着可以使用变量、表达式、条件控制语句、循环语句等,来完成比较复杂的功能!

P1:定义变量

 

-- 定义一个int类型变量、并赋默认值为10
DELIMITER $

CREATE PROCEDURE pro_test1()
BEGIN
        DECLARE num INT DEFAULT 10;   -- 定义变量
        SELECT num;                   -- 查询变量
END$

DELIMITER ;

-- 调用pro_test1存储过程
CALL pro_test1();
-- 标准语法
SET 变量名 = 变量值;

-- 定义字符串类型变量,并赋值
DELIMITER $

CREATE PROCEDURE pro_test2()
BEGIN
        DECLARE NAME VARCHAR(10);   -- 定义变量
        SET NAME = '存储过程';       -- 为变量赋值
        SELECT NAME;                -- 查询变量
END$

DELIMITER ;

-- 调用pro_test2存储过程
CALL pro_test2();

-- 定义两个int变量,用于存储男女同学的总分数
DELIMITER $

CREATE PROCEDURE pro_test3()
BEGIN
        DECLARE men,women INT;  -- 定义变量
        SELECT SUM(score) INTO men FROM student WHERE gender='男';    -- 计算男同学总分数赋值给men
        SELECT SUM(score) INTO women FROM student WHERE gender='女';  -- 计算女同学总分数赋值给women
        SELECT men,women;           -- 查询变量
END$

DELIMITER ;

-- 调用pro_test3存储过程
CALL pro_test3();

P2:if语句的使用

练 习
DELIMITER $

CREATE PROCEDURE pro_test4()
BEGIN
        -- 定义总分数变量
        DECLARE total INT;
        -- 定义分数描述变量
        DECLARE description VARCHAR(10);
        -- 为总分数变量赋值
        SELECT SUM(score) INTO total FROM student;
        -- 判断总分数
        IF total >= 380 THEN 
                SET description = '学习优秀';
        ELSEIF total >= 320 AND total < 380 THEN 
                SET description = '学习不错';
        ELSE 
                SET description = '学习一般';
        END IF;
        
        -- 查询总成绩和描述信息
        SELECT total,description;
END$

DELIMITER ;

-- 调用pro_test4存储过程
CALL pro_test4();

 P3:参数的传递

 

--输入练习
DELIMITER $

CREATE PROCEDURE pro_test5(IN total INT)
BEGIN
        -- 定义分数描述变量
        DECLARE description VARCHAR(10);
        -- 判断总分数
        IF total >= 380 THEN 
                SET description = '学习优秀';
        ELSEIF total >= 320 AND total < 380 THEN 
                SET description = '学习不错';
        ELSE 
                SET description = '学习一般';
        END IF;
        
        -- 查询总成绩和描述信息
        SELECT total,description;
END$

DELIMITER ;

-- 调用pro_test5存储过程
CALL pro_test5(390);
CALL pro_test5((SELECT SUM(score) FROM student));

--输出练习
DELIMITER $

CREATE PROCEDURE pro_test6(IN total INT,OUT description VARCHAR(10))
BEGIN
        -- 判断总分数
        IF total >= 380 THEN 
                SET description = '学习优秀';
        ELSEIF total >= 320 AND total < 380 THEN 
                SET description = '学习不错';
        ELSE 
                SET description = '学习一般';
        END IF;
END$

DELIMITER ;

-- 调用pro_test6存储过程
CALL pro_test6(310,@description);

-- 查询总成绩描述
SELECT @description;

 P4:case语句使用

 

练 习
DELIMITER $

CREATE PROCEDURE pro_test7(IN total INT)
BEGIN
        -- 定义变量
        DECLARE description VARCHAR(10);
        -- 使用case判断
        CASE
        WHEN total >= 380 THEN
                SET description = '学习优秀';
        WHEN total >= 320 AND total < 380 THEN
                SET description = '学习不错';
        ELSE 
                SET description = '学习一般';
        END CASE;
        
        -- 查询分数描述信息
        SELECT description;
END$

DELIMITER ;

-- 调用pro_test7存储过程
CALL pro_test7(390);
CALL pro_test7((SELECT SUM(score) FROM student));

P5 While语句使用

练习:计算1-100之间的偶数和
DELIMITER $

CREATE PROCEDURE pro_test8()
BEGIN
        -- 定义求和变量
        DECLARE result INT DEFAULT 0;
        -- 定义初始化变量
        DECLARE num INT DEFAULT 1;
        -- while循环
        WHILE num <= 100 DO
                -- 偶数判断
                IF num%2=0 THEN
                        SET result = result + num; -- 累加
                END IF;
                
                -- 让num+1
                SET num = num + 1;         
        END WHILE;
        
        -- 查询求和结果
        SELECT result;
END$

DELIMITER ;

-- 调用pro_test8存储过程
CALL pro_test8();

 P6 repeat循环

 

练习:计算1~10之间的和

DELIMITER $

CREATE PROCEDURE pro_test9()
BEGIN
        -- 定义求和变量
        DECLARE result INT DEFAULT 0;
        -- 定义初始化变量
        DECLARE num INT DEFAULT 1;
        -- repeat循环
        REPEAT
                -- 累加
                SET result = result + num;
                -- 让num+1
                SET num = num + 1;
                
                -- 停止循环
                UNTIL num>10
        END REPEAT;
        
        -- 查询求和结果
        SELECT result;
END$

DELIMITER ;

-- 调用pro_test9存储过程
CALL pro_test9();

P7 loop循环

练习:计算1~10之间的和
DELIMITER $

CREATE PROCEDURE pro_test10()
BEGIN
        -- 定义求和变量
        DECLARE result INT DEFAULT 0;
        -- 定义初始化变量
        DECLARE num INT DEFAULT 1;
        -- loop循环
        l:LOOP
                -- 条件成立,停止循环
                IF num > 10 THEN
                        LEAVE l;
                END IF;
        
                -- 累加
                SET result = result + num;
                -- 让num+1
                SET num = num + 1;
        END LOOP l;
        
        -- 查询求和结果
        SELECT result;
END$

DELIMITER ;

-- 调用pro_test10存储过程
CALL pro_test10();

P8 游标

(1)游标的概念

  • 游标可以遍历返回的多行结果,每次拿到一整行数据

  • 在存储过程和函数中可以使用游标对结果集进行循环的处理

  • 简单来说游标就类似于集合的迭代器遍历

  • MySQL中的游标只能用在存储过程和函数中

 

-- 创建stu_score表
CREATE TABLE stu_score(
        id INT PRIMARY KEY AUTO_INCREMENT,
        score INT
);

/*
        将student表中所有的成绩保存到stu_score表中
*/
DELIMITER $

CREATE PROCEDURE pro_test11()
BEGIN
        -- 定义成绩变量
        DECLARE s_score INT;
        -- 创建游标,查询所有学生成绩数据
        DECLARE stu_result CURSOR FOR SELECT score FROM student;
        
        -- 开启游标
        OPEN stu_result;
        
        -- 使用游标,遍历结果,拿到第1行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 使用游标,遍历结果,拿到第2行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 使用游标,遍历结果,拿到第3行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 使用游标,遍历结果,拿到第4行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 关闭游标
        CLOSE stu_result;
END$

DELIMITER ;

-- 调用pro_test11存储过程
CALL pro_test11();

-- 查询stu_score表
SELECT * FROM stu_score;


-- ===========================================================
/*
        出现的问题:
                student表中一共有4条数据,我们在游标遍历了4次,没有问题!
                但是在游标中多遍历几次呢?就会出现问题
*/
DELIMITER $

CREATE PROCEDURE pro_test11()
BEGIN
        -- 定义成绩变量
        DECLARE s_score INT;
        -- 创建游标,查询所有学生成绩数据
        DECLARE stu_result CURSOR FOR SELECT score FROM student;
        
        -- 开启游标
        OPEN stu_result;
        
        -- 使用游标,遍历结果,拿到第1行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 使用游标,遍历结果,拿到第2行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 使用游标,遍历结果,拿到第3行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 使用游标,遍历结果,拿到第4行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 使用游标,遍历结果,拿到第5行数据
        FETCH stu_result INTO s_score;
        -- 将数据保存到stu_score表中
        INSERT INTO stu_score VALUES (NULL,s_score);
        
        -- 关闭游标
        CLOSE stu_result;
END$

DELIMITER ;

-- 调用pro_test11存储过程
CALL pro_test11();

-- 查询stu_score表,虽然数据正确,但是在执行存储过程时会报错
SELECT * FROM stu_score;

 

/*
        将student表中所有的成绩保存到stu_score表中
*/
DELIMITER $

CREATE PROCEDURE pro_test12()
BEGIN
        -- 定义成绩变量
        DECLARE s_score INT;
        -- 定义标记变量
        DECLARE flag INT DEFAULT 0;
        -- 创建游标,查询所有学生成绩数据
        DECLARE stu_result CURSOR FOR SELECT score FROM student;
        -- 游标结束后,将标记变量改为1
        DECLARE EXIT HANDLER FOR NOT FOUND SET flag = 1;
        
        -- 开启游标
        OPEN stu_result;
        
        -- 循环使用游标
        REPEAT
                -- 使用游标,遍历结果,拿到数据
                FETCH stu_result INTO s_score;
                -- 将数据保存到stu_score表中
                INSERT INTO stu_score VALUES (NULL,s_score);
        UNTIL flag=1
        END REPEAT;
        
        -- 关闭游标
        CLOSE stu_result;
END$

DELIMITER ;

-- 调用pro_test12存储过程
CALL pro_test12();

-- 查询stu_score表
SELECT * FROM stu_score;

(2)存储函数

  • 存储函数和存储过程是非常相似的。存储函数可以做的事情,存储过程也可以做到!
  • 存储函数有返回值,存储过程没有返回值(参数的out其实也相当于是返回数据了)

 

练 习
DELIMITER $

CREATE FUNCTION fun_test1()
RETURNS INT
BEGIN
        -- 定义统计变量
        DECLARE result INT;
        -- 查询成绩大于95分的学生数量,给统计变量赋值
        SELECT COUNT(*) INTO result FROM student WHERE score > 95;
        -- 返回统计结果
        RETURN result;
END$

DELIMITER ;

-- 调用fun_test1存储函数
SELECT fun_test1();

3 MYSQL触发器

(1) 概念

  • 触发器是与表有关的数据库对象,可以在 insert/update/delete 之前或之后,触发并执行触发器中定义的SQL语句。触发器的这种特性可以协助应用在数据库端确保数据的完整性 、日志记录 、数据校验等操作 。
  • 使用别名 NEW 和 OLD 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发。

 (2)语法

 

练 习
-- 创建db9数据库
CREATE DATABASE db9;

-- 使用db9数据库
USE db9;

-- 创建账户表account
CREATE TABLE account(
        id INT PRIMARY KEY AUTO_INCREMENT,        -- 账户id
        NAME VARCHAR(20),                                        -- 姓名
        money DOUBLE                                                -- 余额
);
-- 添加数据
INSERT INTO account VALUES (NULL,'张三',1000),(NULL,'李四',2000);

-- 创建日志表account_log
CREATE TABLE account_log(
        id INT PRIMARY KEY AUTO_INCREMENT,     -- 日志id
        operation VARCHAR(20),                 -- 操作类型 (insert update delete)
        operation_time DATETIME,               -- 操作时间
        operation_id INT,                      -- 操作表的id
        operation_params VARCHAR(200)           -- 操作参数
);

-- 创建INSERT触发器
DELIMITER $

CREATE TRIGGER account_insert
AFTER INSERT
ON account
FOR EACH ROW
BEGIN
INSERT INTO account_log VALUES (NULL,'INSERT',NOW(),new.id,CONCAT('插入后id= ',new.id,',name= ',new.name,',money= ',new.money));

END$

DELIMITER ;

-- 向account表添加记录
INSERT INTO account VALUES (NULL,'王五',3000);

-- 查询account表
SELECT * FROM account;

-- 查询日志表
SELECT * FROM account_log;

ps:concat()函数的作用是:将多个字符串连接成一个字符串

-------------------------------------------------------------------------------

-- 创建UPDATE触发器
DELIMITER $

CREATE TRIGGER account_update
AFTER UPDATE
ON account
FOR EACH ROW
BEGIN
        INSERT INTO account_log VALUES (NULL,'UPDATE',NOW(),new.id,CONCAT(
 '修改前 id=',old.id,',name=',old.name,',money=',old.money ,'修改后 id=',new.id,',name=',new.name,',money=',new.money));
END$

DELIMITER ;

-- 修改account表
UPDATE account SET money=3500 WHERE id=3;

-- 查询account表
SELECT * FROM account;

-- 查询日志表
SELECT * FROM account_log;

---------------------------------------------------------------------------------

-- 创建DELETE触发器
DELIMITER $

CREATE TRIGGER account_delete
AFTER DELETE
ON account
FOR EACH ROW
BEGIN
        INSERT INTO account_log VALUES (NULL,'DELETE',NOW(),old.id,CONCAT('删除前id= ',old.id,',name= ',old.name,',money= ',old.money));  
END$

DELIMITER ;

-- 删除account表数据
DELETE FROM account WHERE id=3;

-- 查询account表
SELECT * FROM account;

-- 查询日志表
SELECT * FROM account_log;

查 看 触 发 器
SHOW TRIGGERS;

删 除 触 发 器
DROP TRIGGER account_delete;

4 MySQL事务

(1) 事务的概念

一条或多条 SQL 语句组成一个执行单元,其特点是这个单元要么同时成功要么同时失败,单元中的每条 SQL 语句都相互依赖,形成一个整体,如果某条 SQL 语句执行失败或者出现错误,那么整个单元就会回滚,撤回到事务最初的状态,如果单元中所有的 SQL 语句都执行成功,则事务就顺利执行。

(2) 为什么要有这个事务?

 

(3) 事物回滚的步骤

  1. 开启事务:记录回滚点,并通知服务器,将要执行一组操作,要么同时成功、要么同时失败

  2. 执行sql语句:执行具体的一条或多条sql语句

  3. 结束事务(提交|回滚)

  • 提交:没出现问题,数据进行更新

  • 回滚:出现问题,数据恢复到开启事务时的状态

 

练 习
-- 创建db10数据库
CREATE DATABASE db10;

-- 使用db10数据库
USE db10;

-- 创建账户表
CREATE TABLE account(
        id INT PRIMARY KEY AUTO_INCREMENT,        -- 账户id
        NAME VARCHAR(20),                        -- 账户名称
        money DOUBLE                                -- 账户余额
);
-- 添加数据
INSERT INTO account VALUES (NULL,'张三',1000),(NULL,'李四',1000);

-- 开启事务
START TRANSACTION;
-- 1.张三账户-500
UPDATE account SET money=money-500 WHERE NAME='张三';
-- 2.李四账户+500
UPDATE account SET money=money+500 WHERE NAME='李四';

-- 回滚事务(出现问题)
ROLLBACK;

-- 提交事务(没出现问题)
COMMIT;

(4)事物的提交方式

1.提交方式 : 自动提交(MySQL默认为自动提交)和手动提交。

2.修改提交方式

3.查看提交方式

PS:提交就是把数据给了数据库,从而改变它。

 

(5)事务的四大特征(ACID)

  • 原子性(atomicity)
    • 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响
  • 一致性(consistency)
    • 一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态
  • 拿转账来说,假设张三和李四两者的钱加起来一共是2000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是2000,这就是事务的一致性
  • 隔离性(isolcation)
    • 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
  • 持久性(durability)
    • 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作

(6)事物的隔离级别

  • 多个客户端操作时 ,各个客户端的事务之间应该是隔离的,相互独立的 , 不受影响的。

  • 而如果多个事务操作同一批数据时,则需要设置不同的隔离级别 , 否则就会产生问题 。

  • 我们先来了解一下四种隔离级别的名称 , 再来看看可能出现的问题

 

(7)事物隔离级别的演示

★脏 读 的 演 示

-- 查询账户表
select * from account;

-- 设置隔离级别为read uncommitted
set global transaction isolation level read uncommitted;

-- 开启事务
start transaction;

-- 转账
update account set money = money - 500 where id = 1;
update account set money = money + 500 where id = 2;

-- 窗口2查询转账结果 ,出现脏读(查询到其他事务未提交的数据)

-- 窗口2查看转账结果后,执行回滚(新建查询的代码在下就是那个窗口2)
rollback;
窗口2 
-- 查询隔离级别
select @@tx_isolation;

-- 开启事务
start transaction;

-- 查询账户表
select * from account;

PS:此处查询的是数据库中的数据,而上一个方框中的查询代码查询的数据是未提交的数据,由于有回滚代码rollback,所以会回滚,并不会影响数据库中的数据,所以两次查询不一样,发生了脏读。

★脏读的问题解决和演示不可读的问题

-- 设置隔离级别为repeatable read
set global transaction isolation level repeatable read;

-- 开启事务
start transaction;

-- 转账
update account set money = money - 500 where id = 1;
update account set money = money + 500 where id = 2;

-- 窗口2查看转账结果,并没有发生变化
(先不要运行commit)运行完窗口2再提交
-- 执行提交事务
commit;
select * from account;
-- 这个时候窗口2只要还在上次事务中,看到的结果都是相同的。只有窗口2结束事务,才能看到变化(不可重复读的问题被解决)
窗口2 
-- 查询隔离级别
select @@tx_isolation;

-- 开启事务
start transaction;

-- 查询账户表
select * from account;

★幻读的问题和解决

-- 设置隔离级别为repeatable read
set global transaction isolation level repeatable read;

-- 开启事务
start transaction;

-- 添加一条记录
INSERT INTO account VALUES (3,'王五',1500);

-- 查询账户表,本窗口可以查看到id为3的结果
SELECT * FROM account;

-- 在窗口2,运行窗口二的代码,
        (不要提交)
-- 提交事务
COMMIT;
-- 查询隔离级别
select @@tx_isolation;

-- 开启事务
start transaction;

-- 查询账户表,查询不到新添加的id为3的记录
select * from account;

-- 添加id为3的一条数据,发现添加失败。出现了幻读
INSERT INTO account VALUES (3,'测试',200);

-- 提交事务
COMMIT;

-- 查询账户表,查询到了新添加的id为3的记录
select * from account;

PS:发现在窗口二,添加数据的时候,一直运行,查询的时候还查不到这个数据。这是因为数据隔离了,只有上面提交了这条数据才能添加上。
解 决 幻 读 的 问 题

窗口1 
-- 设置隔离级别为serializable 
set global transaction isolation level serializable; 
-- 开启事务 
start transaction; 
-- 添加一条记录 
INSERT INTO account VALUES (4,'赵六',1600); 
-- 查询账户表,本窗口可以查看到id为4的结果 
SELECT * FROM account; 
/* 
窗口2 
*/
-- 查询隔离级别 

-- 提交事务 
COMMIT; 

窗口2
select @@tx_isolation; 
-- 开启事务 
start transaction; 
-- 查询账户表,发现查询语句无法执行,数据表被锁住!只有窗口1提交事务后,才可以继续操作 
select * from account; 
-- 添加id为4的一条数据,发现已经存在了,就不会再添加了!幻读的问题被解决 
INSERT INTO account VALUES (4,'测试',200); 
-- 提交事务 
COMMIT;

(8)事物隔离级别总结

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值