数据库事务及隔离级别
成都创新互联是一家以网站建设、网页设计、品牌设计、软件运维、seo优化、小程序App开发等移动开发为一体互联网公司。已累计为成都广告推广等众行业中小客户提供优质的互联网建站和软件开发服务。
隔离级别:脏读、幻读、一致读、不可重复读、更新丢失
1.脏读(Dirty Reads):一个事务开始读取了某行数据但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险很可能所有操作都被回滚
2.幻读(Phantom Reads):也称为幻像(幻影)。事务在操作过程中进行两次查询,第二次查询结果包含了第一次查询中未出现的数据(这里并不要求两次查询SQL语句相同)这是因为在两次查询过程中有另外一个事务插入数据造成的
3.不可重复读(Non-repeatable Reads):一个事务对同一行数据重复读取两次但是却得到了不同结果。例如在两次读取中途有另外一个事务对该行数据进行了修改并提交
4.两次更新问题(Second lost updates problem):无法重复读取特例,有两个并发事务同时读取同一行数据然后其中一个对它进行修改提交而另一个也进行了修改提交这就会造成第一次写操作失效
5.更新丢失(Lost update):两个事务都同时更新一行数据但是第二个事务却中途失败退出导致对数据两个修改都失效了这是系统没有执行任何锁操作因此并发事务并没有被隔离开
20、锁是什么?
锁:在所有的DBMS(数据库管理系统)中,锁是实现事务的关键,锁可以保证事务的完整性和并发性。与现实生活中锁一样,它可以使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。当然锁还分级别的。
锁分为行级锁和表锁。
行级锁:主要是在执行操作过程中,锁定指定的行。
主要的锁行语句有:insert ,update,delete ,及select ....for update。
表锁:指在运行操作指令过程中,由用户指定锁定某张表。lock table XXX in mode share;
共享锁,排他锁,共享排它,行共享,行排他。
锁模式包括?
共享锁:(读取)操作创建的锁。其他用户可以并发读取数据,但任何事物都不能获取数据上的排它锁,直到已释放所有共享锁。
排他锁(X锁):对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
更新锁:更新 (U) 锁可以防止通常形式的死锁。如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则两个事务需都要转换共享锁为排它 (X) 锁,并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。
若要避免这种潜 在的死锁问题,请使用更新 (U) 锁。一次只有一个事务可以获得资源的更新 (U) 锁。如果事务修改资源,则更新 (U) 锁转换为排它 (X) 锁。否则,锁转换为共享锁。
锁的粒度主要有以下几种类型:
行锁: 粒度最小,并发性最高
页锁:一次锁定一页。25个行锁可升级为一个页锁。
表锁:粒度大,并发性低
数据库锁:控制整个数据库操作
乐观锁:乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。一般的实现乐观锁的方式就是记录数据版本。
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁,读锁,写锁等,都是在做操作之前先上锁。
20、数据库的乐观锁和悲观锁是什么? oracle 是行级锁
数据库管理系统(DBMS)中,并发控制的任务是:确保在多个事务同时存取同一数据时,不破坏事务的隔离性和统一性以及数据库的统一性。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
21、悲观锁和乐观锁的区别,怎么实现
悲观锁:一段执行逻辑加上悲观锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。
乐观锁:一段执行逻辑加上乐观锁,不同线程同时执行时,可以同时进入执行,在最后更新数据的时候要检查这些数据是否被其他线程修改了(版本和执行初是否相同),没有修改则进行更新,否则放弃本次操作。
首选你需要了解一下 数据脏读,幻读,等一些概念,其次是你要了解一下锁这个概念,当一条数据被读取时,处于锁状态,其他的用户无法对其进行操作。
1.设置为可重复读
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
2.首先TB做出一次查询,此时name为bb
3.TA对数据进行修改,并提交
4.此时加入session C作为对比,使用自动事务并做出查询,可见数据已经被修改
5.在已经开启事务的TB中,查询到的,仍然是数据开启事务之前的状态,所以数据是可重复读的
可重复读隔离级别中,每当事务开始后,第一次执行sql语句时(或者执行START TRANSACTION WITH CONSISTENT SNAPSHOT)MVCC会建立一个read view,选取当时的系统版本号,作为事务版本号,以Undo log的行系统版本号与事务版本号进行对比,增删改查都要遵循如下模式:
SELECT:
1, InnoDB只查找版本早于当前事务版本的数据行(行的系统版本号小于等于事务版本号),这样可以确保事务读取的行,要么是事务开始前就存在的,要么是事务自身插入的或修改过的。
2, 行的删除号要么未定义,要么大于当前事务版本号,这样可以确保事务读取到的行,在事务开始之前未被删除。
INSERT:
InnoDB 为新插入的每一行保存当前系统版本号做为行版本号。
DELETE:
INNODB 为删除的每一行保存当前系统版本号作为行删除标识。
UPDATE:
InnoDB 为插入的每一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
所以READ COMMITTED和REPEATABLE READ的区别在于,READ COMMITTED总是读取被锁定行的最新一份快照数据, 所以会有不可重复读的问题。而REPEATABLE READ读取事务开始时行系统版本号小于事务版本号的数据,解决不可重复读的问题。
此外要提的一点是,MySql的REPEATABLE READ与Oracle的不同,不但解决了不可重复读问题,还解决的“幻读”问题。
幻读的产生:遵循上述增删改查模式,假设TA事务的事物版本号为3,TB早于TA开启事务,TB事物版本号为2,TB先新增一条数据,行数据的版本号为2,并提交。TB提交后,TA查询时,满足“行的系统版本号小于等于事务版本号”的条件,可以查到数据,形成“幻读”。
InnoDB采用Next-key Lock(间隙锁)来避免“幻读”问题。
Record Lock:单个行记录的锁,锁定的是索引而非记录本身。
GAP Lock:间隙锁,锁定一个范围,但不包含记录本身。
Next-Key Lock:Gap Lock+Record Lock 锁定一个范围并锁定记录本身。
举例说明:
某表字段为ID和NAME,有3条睡觉,ID分别为10,20,50。
如果索引为 10,20,50,那么:
Record Lock:select * from tab where id = 10 for update; //对id=10单行进行加锁
Gap Lock锁范围:(-∞,10)(10,20)(20,50)(50,+∞)
Next-Key Lock锁范围:(-∞,10] (10,20] (20,50] (50,+∞)
当查询的索引含有唯一属性时,InnoDB会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁住索引本身,而不是范围。
虽然避免了幻读问题,但是还有个特殊情况,感觉可以叫做“幻改”,即当前事务修改了本身并不能查询到的数据。这也是MVCC造成的假象,当前事务虽然查询不到其他事务提交的数据,但是可以对其他事务提交的数据进行修改。
事务隔离的四个级别是未提交读(Read Uncommitted)、提交读(Read Committed)、可重复读(Repeable Read)、可串行化(Serializable)。
1、未提交读(Read Uncommitted):事务可以读取未提交的数据,也称作脏读(Dirty Read)。一般很少使用。
2、提交读(Read Committed):是大都是DBMS(如:Oracle,SQLServer)默认事务隔离。执行两次同意的查询却有不同的结果,也叫不可重复读。
3、可重复读(Repeable Read):是MySQL默认事务隔离级别。能确保同一事务多次读取同一数据的结果是一致的。可以解决脏读的问题,但理论上无法解决幻读(Phantom Read)的问题。
4、可串行化(Serializable):是最高的隔离级别。强制事务串行执行,会在读取的每一行数据上加锁,这样虽然能避免幻读的问题,但也可能导致大量的超时和锁争用的问题。很少会应用到这种级别,只有在非常需要确保数据的一致性且可以接受没有并发的应用场景下才会考虑。
事务隔离级别特点比较
从事务隔离级别的定义上可以看出,Serializable级别隔离性最高,但是其效率也最低,因为其要求所有操作相同记录的事务都串行的执行。
对于MySql而言,其默认事务级别是Repeatable read,虽然在定义上讲,这种隔离级别无法解决幻读的问题,但是MySql使用了一种Next key-lock的算法来实现Repeatable read,这种算法是能够解决幻读问题的。
关于Next key-lock算法,在进行查询时,其不仅会将当前的操作记录锁住,也会将查询所涉及到的范围锁住。
也就是说,其他事务如果想要在当前事务查询的范围内进行数据操作,那么其是会被阻塞的,因而MySql在Repeatable read隔离级别下就已经具备了Serializable隔离级别的事务隔离性。
以上内容参考:百度百科-隔离级别
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
• 脏读: 对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
• 不可重复读: 对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
• 幻读: 对于两个事物 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题.
一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱
数据库提供了4中隔离级别:
隔离级别 描述
READ UNCOMMITTED(读未提交数据) 允许事务读取未被其他事务提交的变更,脏读、不可重复读和幻读的问题都会出现
READ COMMITED(读已提交数据) 只允许事务读取已经被其他事务提交的变更,可以避免脏读,但不可重复读和幻读问题仍然会出现
REPEATABLE READ(可重复读) 确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读,但幻读的问题依然存在
SERIALIZABLE(串行化) 确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,所有并发问题都可以避免,但性能十分低
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE. Oracle 默认的事务隔离级别为: READ COMMITED
Mysql 支持 4 中事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ
1.查看当前会话隔离级别
select @@tx_isolation;
2.查看系统当前隔离级别
select @@global.tx_isolation;
3.设置当前会话隔离级别
set session transaction isolatin level repeatable read;
4.设置系统当前隔离级别
set global transaction isolation level repeatable read;
5.命令行,开始事务时
set autocommit=off 或者 start transaction
关于隔离级别的理解
1.read uncommitted
可以看到未提交的数据(脏读),举个例子:别人说的话你都相信了,但是可能他只是说说,并不实际做。
2.read committed
读取提交的数据。但是,可能多次读取的数据结果不一致(不可重复读,幻读)。用读写的观点就是:读取的行数据,可以写。
3.repeatable read(MySQL默认隔离级别)
可以重复读取,但有幻读。读写观点:读取的数据行不可写,但是可以往表中新增数据。在MySQL中,其他事务新增的数据,看不到,不会产生幻读。采用多版本并发控制(MVCC)机制解决幻读问题。
4.serializable
可读,不可写。像java中的锁,写数据必须等待另一个事务结束。