1 0
1
什么是事物?
事物可以理解成一组操作,要么都执行,要么都不执行。
比如银行转账,A账户有100块钱,B账户有0块钱,A转给B100,需要先从A中扣除100,然后在给B账户加100。当钱从A账户扣除100的时候,银行突然停电导致系统不继续运转了,最终导致的结果是A账户的100已经扣除,但是B账户并没有收到。
2 0
1
事务的四个特性
•原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
•一致性:执行事务前后,数据保持一致;
•隔离性:并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;
•持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
3 0
1
并发性高的时候可能带来的问题
•脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
•丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
•不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
•幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,称为幻读。
不可重复度和幻读区别:
不可重复读的重点是修改,幻读的重点在于新增或者删除。
4 0
1
事务的隔离级别
read-uncommitted(读取未提交): 隔离级别最低,允许读取事物中未提交的数据,并发的多个事物之间可能会出现脏读,幻读,不可重复读等问题。
read-committed(读取已提交):允许读取其他事物已提交的数据,可以避免脏读,但是幻读和不可重复读仍然可能出现。
repeatable-read(可重复读):对同一条数据或同一个字段的多次读取结果一样,除非数据是被自己事物修改,这种隔离级别可以避免脏读和不可重复读,但是幻读有可能会出现。
serializable(可串行化):最高的隔离级别,完全符合ACID的隔离级别,所有事物之间串行,依次执行,各个事物之间互不干扰,可以避免脏读幻读和不可重复读,但是效率低并发性差。
mysql中的InnoDB引擎中默认的隔离级别是repeatable-read(可重复读)
这是一张InnoDB引擎的表,在控制台输入命令select @@tx_isolation 查询事物隔离级别
事物处理相关的命令:
start tarnsaction :开启一个事物。
commit:提交一个事物,会让sql对数据库的修改变成持久性。
rollback:回滚,结束当前事物并撤回所有未提交的修改。
下面我们来模拟一下高并发场景:
首先先建一个测试用的表:
5 0
1
读取未提交(脏读)
更改事物隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;(读取未提交)
第一步先开启一个事物A,然后查询id为1的数据结果为
第二步开启事物B,然后把id为1的数据address_code字段的值改为“1111”
然后不提交事物B,转回来在事物A中做第二次查询,查询结果为
然后我们再去数据表中查看
结果为:事物B并没有提交,但是事物A把事物B未提交的数据读出来了,并且数据表中的数据也没有变化,这就出现了脏读的现象。如果这时我们用事物A读出来的脏数据去继续操作,程序很可能就报错了。
6 0
1
读已提交(read-committed)
读已提交的操作跟上述流程一样:
将隔离级别设置为读已提交read-committed
然后在第二个事物更改操作不提交时我们去事物A查询,会发现数据不变,
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
第一次查询结果
事物B更改数据不提交,转到A事物第二次查询结果为
read-committed隔离级别帮我们成功避免了脏读,但是不可重复读和幻读仍然可能出现。
7 0
1
可重复读(repeatable-read)
我们常用的InnoDB引擎默认的隔离级别就是repeatable-read,
我们先将隔离级别调回repeatable-read,
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
我们还是先开启事物A并进行第一次查询
结果为“1111”
这时候我们开启事物B,并且对该数据做一次修改但是不提交
修改后事物B查询出来的为修改后的“2222”
这时候我们看数据库数据并没有变化
然后用事物A进行第二次查询,结果为
最后我们提交事物B,再用事物A进行第三次查询,
数据库表数据已经变成了事物B修改后的“2222”
最后事物A查询出来的结果仍然是“1111”
说明repeatable-read隔离级别中,其他事物对数据的修改不会影响另一个事物的读取操作
多次读取数据一样,叫可重复读。
最后我们在对repeatable-read隔离级别做一次幻读实验:
表中有七条数据,我们开启事物A做一次查询所有,
然后用事物B插入一条数据,但是不提交事物
再次用事物A查询,结果仍然为7条没有新插入的数据
然后我们提交事物B在来对事物A做第三次查询
最后我们发现,事物B提交以后,数据库表中正常增加了一条数据“博物馆”,但是事物A中第三次查询
结果和第一次一样,结论是:repeatable-read隔离级别有避免幻读的作用。
InnoDB中repeatable-read是采用什么来避免幻读的?
在快照读取情况下,mysql通过mvcc来避免幻读。
在当前读取情况下,mysql通过next-key来避免幻读,有兴趣的自行了解。
当事务B修改数据并提交之后,事务A读出来的数据显然和事务B提交的数据不一样,那么事务A的数据是从哪里读出来的?
涉及到的概念:
Redo Log:记录了数据操作在物理层面的修改,mysql中使用了大量缓存,修改操作时会直接修改内存,而不是立刻修改磁盘,事务进行中时会不断的产生redo log,在事务提交时进行一次flush操作,保存到磁盘中。当数据库或主机失效重启时,会根据redo log进行数据的恢复,如果redo log中有事务提交,则进行事务提交修改数据。
Undo Log:除了记录redo log外,当使用事务的时候还会记录undo log,undo log用于数据的撤回操作,它记录了修改的反向操作,比如,插入对应删除,修改对应修改为原来的数据,通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC
MVCC:Mysql中用的一个多并发版本控制,跟乐观锁相似,通过版本号控制
交易担保 千家企业简历 快快加入我们带你飞~~ Mini Program
在看点这里