事务
执行某一任务之前,先要给当前状态一个快照(保存了数据库的当前所有状态),然后再具体执行某一系列操作。
事务的基本要素:
1、原子性:事务开始执行的过程中,所有的操作要么全部做完,要么全部都不做,事务执行的过程中出错,就会回滚到事务开始前的状态,事务就是一个不可分割的整体。
2、一致性:当多个事务共同操作数据库的时候,各个事务读取的数据应该都是一致的。
3、隔离性:多个事务并发时,彼此之间的相互影响的程度。
4、持久性:当事务完成提交之后,事务对数据库的所有更新将被保存到数据库中。
事务的并发问题
1、脏读:
-
事务A读取了事务B正在更新过程中的数据(操作的过程中),然后B回滚操作,那么A读取到的数据是脏数据
-
脏读就是一个事务A去读另一个事务B的快照内容,因为不确定事务B的操作是否要生效,所以可能会产生脏读的问题。
2、不可重复读:
- 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交(操作完成了),导致事务A此时读取同一数据时,和之前读取的结果不一致。
- 事务A读取的是数据库里面的内容,所以当事务B提交了之后会改变数据库里面的内容,所以会出现事务A两次查询的结果不一致。
3、幻读:
-
系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
事务隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
mysql默认事务隔离级别是rr
事务的具体操作
1、当一个端口操作开启了事务,另一个端口却未开启事务的时候。
-
开启事务修改
-
未开启事务查询
从这里可见,开启事务和未开启事务的查询结果不一致,这是因为开启事务的操作未提交(commit)。
2、修改事务的隔离级别
-
修改当前连接的隔离级别
set session transaction_isolation=‘隔离级别’;
打开事务:
start transaction;
-
修改全局的隔离级别
3、读未提交:
(1)打开一个客户端A,并设置当前事务模式为read uncommitted(未提交读),查询表tb_user的初始值,并更新表(此时未提交)
(2)打开另一个客户端B,并查询表tb_user:
4、读已提交
(1)打开一个客户端A,并设置当前事务模式为read committed(未提交读),查询表tb_user的所有记录,并修username属性值,然后提交:
(2)客户端B设置隔离级别为rc,客户端B先查询数据库,然后客户端A已经提交,客户端B再继续查询,结果与上一步不一致,即产生了不可重复读的问题
5、可重复读
(1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表tb_user的所有记录,并修改其中一条记录,并提交。
(2)重新打开一个客户端B,并设置当前事务模式为repeatable read,查询表tb_user的所有记录,然后等待客户端A修改并提交之后,然后在查询一次。
可以看出,两次结果一致,并没有出现不可重复读的问题。此时事务B读取的是启动事务的时候产生自己的快照,所以当事务A提交了之后就算会改变数据库里面的内容,也不会影响事务B的查询结果。
4.串行化
(1)打开一个客户端A,并设置当前事务模式为serializable,查询表tb_suer的初始值。
注意:
- 事务隔离级别为读提交时,写数据只会锁住相应的行
- 事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
- 事务隔离级别为串行化时,读写数据都会锁住整张表
- 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。