个人主页:程序员阿红
生活平淡,用心就会发光,岁月沉闷,跑起来,就会有风
推荐文章:
【毕业季·进击的技术er】忆毕业一年有感
Java 学习路线一条龙版
一语详解SpringBoot全局配置文件
一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库. 数据库的相同数据可能被多个事务同时访问,如果不采取隔离措施,就会导致各种问题, 破坏数据的完整性
事务在操作时的理想状态: 所有的事务之间保持隔离,互不影响。因为并发操作,多个用户同时访问同一个 数据。可能引发并发访问的问题
通过设置隔离级别,可以防止上面的三种并发问题.
MySQL数据库有四种隔离级别 上面的级别最低,下面的级别最高。
select @@tx_isolation;
set global transaction isolation level 级别名称;
read uncommitted 读未提交
read committed 读已提交
repeatable read 可重复读
serializable 串行化
例如: 修改隔离级别为 读未提交
set global transaction isolation level read uncommitted;
脏读: 一个事务读取到了另一个事务中尚未提交的数据
(1)打开窗口登录 MySQL,设置全局的隔离级别为最低
use db2;
set global transaction isolation level read uncommitted;
(2)关闭窗口,开一个新的窗口A ,再次查询隔离级别
select @@tx_isolation;
(3) 再开启一个新的窗口 B
use db2;
start transaction;
select * from account;
-- 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;
rollback;
select * from account;
脏读非常危险的,比如张三向李四购买商品,张三开启事务,向李四账号转入 500 块,然后打电话给李四说钱 已经转了。李四一查询钱到账了,发货给张三。张三收到货后回滚事务,李四的再查看钱没了。
解决方案
将全局的隔离级别进行提升为: read committed
在 A 窗口设置全局的隔离级别为 read committed
set global transaction isolation level read committed;
重新开启A窗口, 查看设置是否成功.
select @@tx_isolation;
-- tom账户 -500元
UPDATE account SET money = money - 500 WHERE NAME = 'tom';
-- jack账户 + 500元
UPDATE account SET money = money + 500 WHERE NAME = 'jack';
mysqlselect * from account;
commit;
select * from account;
不可重复读: 同一个事务中,进行查询操作,但是每次读取的数据内容是不一样的
use db2;
start transaction;
2.1 B 窗口开启事务后, 先进行一次数据查询
select * from account;
2.2 在 A 窗口开启事务后,将用户tom的账户 + 500 ,然后提交事务
-- 修改数据
update account set money = money + 500 where name = 'tom';
-- 提交事务
commit;
两次查询输出的结果不同,到底哪次是对的?
不知道以哪次为准。 很多人认为这种情况就对了,无须困惑, 当然是后面的为准。
比如银行程序需要将查询结果分别输出到电脑屏幕和发短信给客 户,结果在一个事务
中针对不同的输出目的地进行的两次查询不一致,导致文件和屏幕中的结果不一致,银
行工作 人员就不知道以哪个为准了
UPDATE account SET money = 1000
-- 查看事务隔离级别
select @@tx_isolation;
-- 设置事务隔离级别为 repeatable read
set global transaction isolation level repeatable read;
select * from account;
-- 修改数据
update account set money = money + 500 where name = 'tom';
-- 提交事务
commit;
select * from account;
幻读: select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。
-- 假设要再添加一条id为3的 数据,在添加之前先判断是否存在
select * from account where id = 3;
INSERT INTO account VALUES(3,'lucy',1000);
commit;
如果一个事务,使用了SERIALIZABLE——可串行化隔离级别时,在这个事务没有被提交之前 , 其他的线程,只能等到当前操作完成之后,才能进行操作,这样会非常耗时,而且,影响数据库的
性能,数据库不会使用这种隔离级别
DELETE FROM account WHERE id = 3;
set global transaction isolation level SERIALIZABLE;
SELECT * FROM account WHERE id = 3;
INSERT INTO account VALUES(3,'lucy',1000);
INSERT INTO account VALUES(3,'lucy',1000);
commit;
完结撒花
如果命运是世上最烂的编剧。 那么你就要争取,做你人生最好的演员
写作不易,如果您觉得写的不错,欢迎给博主点赞、收藏、评论来一波~让博主更有动力吧