01.MySQL 事务隔离级别及并发访问数据库问题

文章目录

  • (一)MySQL 事务隔离级别
    • 1.数据并发访问
    • 2.并发访问会产生的问题
    • 3.四种隔离级别
    • 4.隔离级别相关命令
  • (二) 隔离性问题演示
    • 1.脏读演示
    • 2.解决脏读问题
    • 3.不可重复读演示
    • 4.解决不可重复读问题
    • 5.幻读演示
    • 6 解决幻读问题

个人主页:程序员阿红
生活平淡,用心就会发光,岁月沉闷,跑起来,就会有风
推荐文章:
【毕业季·进击的技术er】忆毕业一年有感
Java 学习路线一条龙版
一语详解SpringBoot全局配置文件

01.MySQL 事务隔离级别及并发访问数据库问题_第1张图片

(一)MySQL 事务隔离级别

1.数据并发访问

一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库. 数据库的相同数据可能被多个事务同时访问,如果不采取隔离措施,就会导致各种问题, 破坏数据的完整性

2.并发访问会产生的问题

事务在操作时的理想状态: 所有的事务之间保持隔离,互不影响。因为并发操作,多个用户同时访问同一个 数据。可能引发并发访问的问题

01.MySQL 事务隔离级别及并发访问数据库问题_第2张图片

3.四种隔离级别

通过设置隔离级别,可以防止上面的三种并发问题.
MySQL数据库有四种隔离级别 上面的级别最低,下面的级别最高。

  • ✔ 会出现问题
  • ✘ 不会出现问题

01.MySQL 事务隔离级别及并发访问数据库问题_第3张图片

4.隔离级别相关命令

  1. 查看隔离级别
select @@tx_isolation;

01.MySQL 事务隔离级别及并发访问数据库问题_第4张图片

  1. 设置事务隔离级别,需要退出 MySQL 再重新登录才能看到隔离级别的变化
set global transaction isolation level 级别名称;
read uncommitted 读未提交
read committed  读已提交
repeatable read 可重复读
serializable   串行化

例如: 修改隔离级别为 读未提交

set global transaction isolation level read uncommitted;

(二) 隔离性问题演示

1.脏读演示

脏读: 一个事务读取到了另一个事务中尚未提交的数据

(1)打开窗口登录 MySQL,设置全局的隔离级别为最低

  1. 登录MySQL

01.MySQL 事务隔离级别及并发访问数据库问题_第5张图片

  1. 使用db2 数据库
use db2;
  1. 设置隔离级别为最低 读未提交
set global transaction isolation level read uncommitted;

image-20220713213616513

(2)关闭窗口,开一个新的窗口A ,再次查询隔离级别

  1. 开启新的 窗口A

01.MySQL 事务隔离级别及并发访问数据库问题_第6张图片

  1. 查询隔离级别
select @@tx_isolation;

01.MySQL 事务隔离级别及并发访问数据库问题_第7张图片

(3) 再开启一个新的窗口 B

  1. 登录数据库

01.MySQL 事务隔离级别及并发访问数据库问题_第8张图片

  1. 选择数据库
use db2;
  1. 开启事务
start transaction;
  1. 查询
select * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第9张图片

  1. A窗口执行

    1. 选择数据库
    use db2;
    
    1. 开启事务
    start transaction;
    

    image-20220713214309765

    1. 执行修改操作
-- tom账户 -500元
UPDATE account SET money = money - 500 WHERE NAME = 'tom';
-- jack账户 + 500元
UPDATE account SET money = money + 500 WHERE NAME = 'jack';

2.B 窗口查询数据

查询账户信息

select * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第10张图片

  1. A窗口转账异常,进行回滚
rollback;

image-20220713214448535

  1. B 窗口再次查询 账户
select * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第11张图片

2.解决脏读问题

  • 脏读非常危险的,比如张三向李四购买商品,张三开启事务,向李四账号转入 500 块,然后打电话给李四说钱 已经转了。李四一查询钱到账了,发货给张三。张三收到货后回滚事务,李四的再查看钱没了。

  • 解决方案
    将全局的隔离级别进行提升为: read committed

  1. 在 A 窗口设置全局的隔离级别为 read committed

    set global transaction isolation level read committed;
    
  2. 重新开启A窗口, 查看设置是否成功.

select @@tx_isolation;
  1. 开启B 窗口, A 和 B 窗口选择数据库后, 都开启事务

01.MySQL 事务隔离级别及并发访问数据库问题_第12张图片

  1. A 窗口 只是更新两个人的账户, 不提交事务
-- tom账户 -500元
UPDATE account SET money = money - 500 WHERE NAME = 'tom';
-- jack账户 + 500元
UPDATE account SET money = money + 500 WHERE NAME = 'jack';
  1. B 窗口进行查询,没有查询到未提交的数据
mysqlselect * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第13张图片

  1. A窗口commit提交数据
commit;
  1. B 窗口查看数据
select * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第14张图片

3.不可重复读演示

不可重复读: 同一个事务中,进行查询操作,但是每次读取的数据内容是不一样的

  1. 恢复数据 (把数据改回初始状态)

01.MySQL 事务隔离级别及并发访问数据库问题_第15张图片

  1. 打开两个 窗口A 和 窗口B,选择数据库后 开启事务
use db2;
start transaction;

01.MySQL 事务隔离级别及并发访问数据库问题_第16张图片

2.1 B 窗口开启事务后, 先进行一次数据查询

select * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第17张图片

2.2 在 A 窗口开启事务后,将用户tom的账户 + 500 ,然后提交事务

-- 修改数据
update account set money = money + 500 where name = 'tom';
-- 提交事务
commit;

01.MySQL 事务隔离级别及并发访问数据库问题_第18张图片

  1. B 窗口再次查询数据

  • 两次查询输出的结果不同,到底哪次是对的?

  • 不知道以哪次为准。 很多人认为这种情况就对了,无须困惑, 当然是后面的为准。

    • 我们可以考虑这样一种情况:

    比如银行程序需要将查询结果分别输出到电脑屏幕和发短信给客 户,结果在一个事务
    中针对不同的输出目的地进行的两次查询不一致,导致文件和屏幕中的结果不一致,银
    行工作 人员就不知道以哪个为准了

4.解决不可重复读问题

  • 将全局的隔离级别进行提升为: repeatable read
  1. 恢复数据
UPDATE account SET money = 1000
  1. 打开A 窗口, 设置隔离级别为:repeatable read
-- 查看事务隔离级别
select @@tx_isolation;
-- 设置事务隔离级别为 repeatable read
set global transaction isolation level repeatable read;

01.MySQL 事务隔离级别及并发访问数据库问题_第19张图片

  1. 重新开启 A,B 窗口 选择数据库 ,同时开启事务

01.MySQL 事务隔离级别及并发访问数据库问题_第20张图片

  1. B 窗口事务 先进行第一次查询
select * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第21张图片

  1. A 窗口更新数据, 然后提交事务
-- 修改数据
update account set money = money + 500 where name = 'tom';
-- 提交事务
commit;
  1. B 窗口 再次查询
select * from account;

01.MySQL 事务隔离级别及并发访问数据库问题_第22张图片

  • 同一个事务中为了保证多次查询数据一致,必须使用 repeatable read 隔离级别

5.幻读演示

幻读: select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。

  1. 打开 A B 窗口, 选择数据库 开启事务

01.MySQL 事务隔离级别及并发访问数据库问题_第23张图片

  1. A 窗口 先执行一次查询操作
-- 假设要再添加一条id为3的 数据,在添加之前先判断是否存在
select * from account where id = 3;

image-20220713215752878

  1. B 窗口 插入一条数据 提交事务
INSERT INTO account VALUES(3,'lucy',1000);
commit;

01.MySQL 事务隔离级别及并发访问数据库问题_第24张图片

  1. A 窗口执行 插入操作, 发现报错. 出现幻读

    01.MySQL 事务隔离级别及并发访问数据库问题_第25张图片见鬼了,我刚才读到的结果应该可以支持我这样操作才对啊,为什么现在不可以

6 解决幻读问题

  • 将事务隔离级别设置到最高 SERIALIZABLE ,以挡住幻读的发生

如果一个事务,使用了SERIALIZABLE——可串行化隔离级别时,在这个事务没有被提交之前 , 其他的线程,只能等到当前操作完成之后,才能进行操作,这样会非常耗时,而且,影响数据库的
性能,数据库不会使用这种隔离级别

  1. 恢复数据
DELETE FROM account WHERE id = 3;
  1. 打开A 窗口 将数据隔离级别提升到最高
set global transaction isolation level SERIALIZABLE;

image-20220713215942483

  1. 打开 A B 窗口, 选择数据库 开启事务

01.MySQL 事务隔离级别及并发访问数据库问题_第26张图片

  1. A 窗口 先执行一次查询操作
SELECT * FROM account WHERE id = 3;
  1. B 窗口插入一条数据
INSERT INTO account VALUES(3,'lucy',1000);

image-20220713220028048

  1. A 窗口执行 插入操作, 提交事务 数据插入成功.
INSERT INTO account VALUES(3,'lucy',1000);
commit;

01.MySQL 事务隔离级别及并发访问数据库问题_第27张图片

  1. B 窗口在 A窗口提交事务之后, 再执行,但是主键冲突出现错误

image-20220713220056672

  • 总结:
    serializable 串行化可以彻底解决幻读,但是 事务只能排队执行,严重影响效率,数据库不会使用这种隔离级别

完结撒花

如果命运是世上最烂的编剧。 那么你就要争取,做你人生最好的演员

写作不易,如果您觉得写的不错,欢迎给博主点赞、收藏、评论来一波~让博主更有动力吧

你可能感兴趣的:(Mysql高级篇,数据库,mysql,java,mysql隔离级别,并发访问数据库)