关系型数据库遵循ACID规则
TRANSACTION(事务)
事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:
1、A (Atomicity) 原子性
原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。
比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。
2、C (Consistency) 一致性
一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。
例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。
3、I (Isolation) 独立性
所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。
比如现在有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。
4、D (Durability) 持久性
持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。
RDBMS隔离级别设置
数据库
set [session | global ] transaction_isolation level 设置事务隔离级别
select @@transaction_isolation 查询当前事务隔离级别
mysql8 以上更改了原来的事务隔离级别字段 以前老版本是 tx_isolation
如果你的版本比较老 就可以改成 tx_isolation 执行就可以了。
设置 描述
Serializable 可避免脏读、不可重复读、虚读情况的发生。(串行化)
Repeatable read 可避免脏读、不可重复读情况的发生。(可重复读)
Read committed 可避免脏读情况发生(读已提交)。
Read uncommitted 最低级别,以上情况均无法保证。(读未提交)
三种不考虑隔离出现的问题:
-
1.脏读
脏读的意思就是在你进行一个事务的同时,读取到了另一个事务未提交的数据
Example:
好比别人在银行转账,错转了一笔1个亿的金额到你的账户里面,最后收回去了:
模拟一下sql:
update account set money = money + 1000000000 where name = ‘yourname’;
update account set money = money - 1000000000 where name = ‘others’;
这两条sql是一个事务,此时别人操作完成 但是并没有提交事务(并没有确定)。
而你恰好这个时候去查了一下你的账户余额:
select money from accout where name = ‘yourname’;
这是一个同时的事务,发现你的账户多出了100000000这么多钱 你很开心,奔走相告,炒了老板鱿鱼,
然后,别人账户发现转错了,开始了回滚,rollback。
然后你的钱就没有了。 等过两天你再去查的时候发现钱没了,你很伤心,哭着打电话给老板求他让你回去上班。
–
-
2.不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
例如事务1在读取某一数据,而事务2突然修改了这个数据并且把事务提交了,事务1这时需要再次读取该数据,然后得到了不同的结果,这就是不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
这里主要是指“update”数据,导致前后读取的数据不一致。 跟幻读需要区分开(后面解释幻读)
Example:
你和小明有一个数据库,专门用来记录你俩一起吃饭的日子。
某一天你们同时想知道上个星期你们什么时候一起吃的饭,然后先后去查了数据库:
你先查:
事务1 part1:
select day_of_week from date_time where time = ‘20200427’;
你获得的结果是"Wednesday" 此时事务还未结束 小明还要查。
事务2:
然后此时柯南中的小黑悄悄登录了你们的数据库,修改了这条记录,改成了"Monday";
update date_time set day_of_week = ‘Monday’ where time = ‘20200427’;
commit
并且提交了该事务,动作十分迅速,只用了零点几秒。
事务1 part2:
然后小明的查询语句才开始作用:
select day_of_week from date_time where time = ‘20200427’;
他得到的结果就是"Monday" 然后他说你查的不对,你又说他查的不对。 然后你们俩互相指责对方根本不在乎对方,扭打在一起,最后不欢而散,形同陌路,好可惜。
-
3.幻读
所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。
但是在可重复读的隔离级别上,会产生幻读的问题。
Example:
小明和他老婆相敬如宾,十分恩爱。
这天小明想给自己的老婆买一个好看的包包,是CHANEL的,买之前,他特意查了下自己老婆的存储宝宝信息的数据库:
事务1 part1:
select count(*) from bag_infor where bag_name = ‘channel’;
结果是0,虽然老婆有20个包包了,但他知道自己从来没有给老婆买过chanel的包包,很惭愧,于是他马上就下单购买。
事务2:
小明老婆在外面有情人,叫隔壁老王,隔壁老王也几乎同时给小明老婆买了个chanel的包包,于是:
insert into bag_info(bag_id, bag_name, worth) values(21, “channel”, “1000000”);
commit;
小明老婆就有了第一个包包。 她也很开心,想到小明从来没给自己买过 她觉得心里很不是滋味
事务1 part2:
然后小明买的包包也到了,就往里面插入自己买的包包:
insert into bag_info(bag_id, bag_name, worth) values(21, “channel”, “10000”);
然后就报错了,主键重复,插入失败!
select count(*) from bag_infor where bag_name = ‘channel’;
他又查询,结果发现还是没有记录呀。
小明百思不得其解 自己买的包包还没有插入啊 咋会突然里面有了一个chanel包包呢。
小明一直被蒙在鼓里 好惨