数据库事务

it2022-05-05  135

 

数据库的事务隔离级别:

1.Read Commited 可读已提交    2.Read Uncommited 可读未提交    3.Repeatable Read 可重复读    4.Serializable 串行化

sqlserver默认的事务隔离级别是:读可提交。

 

各种并发问题

1. 第一类丢失更新(lost update): 在完全未隔离事务的情况下,两个事物更新同一条数据资源,某一事物异常终止,回滚造成第一个完成的更新也同时丢失。

 事务1事务21开启事务 2 开启事务3取出数据 age=20 4 取出数据 age=205更新数据 age=30 6 更新数据 age=35,并提交事务7回滚事务 

 

 

在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,T4时刻事务2取出了同一条数据,T5时刻事务1将age字段值更新为30,T6时刻事务2更新age为35并提交了数据,但是T7事务1回滚了事务age最后的值依然为20,事务2的更新丢失了,这种情况就叫做"第一类丢失更新(lost update)"。

2. 脏读(dirty read):如果第二个事务查询到第一个事务还未提交的更新数据,形成脏读。

 事务1事务21开启事务 2 开启事务3取出数据 age=20 4  5更新 age=30 6 读取数据 age=30(脏读)7  

 

在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,在T5时刻事务1将age的值更新为30,但是事务还未提交,T6时刻事务2读取同一条记录,获得age的值为30,但是事务1还未提交,若在T7时刻事务1回滚了事务2的数据就是错误的数据(脏数据),这种情况叫做" 脏读(dirty read)"。

3. 虚读(phantom read):一个事务执行两次查询,第二次结果集包含第一次中没有或者某些行已被删除,造成两次结果不一致,只是另一个事务在这两次查询中间插入或者删除了数据造成的。

 事务1事务21开启事务 2 开启事务3查询数据,有一条记录 4 插入一条记录5  6 提交事务7查询数据,有2条记录 

 

在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1从数据库中查询所有记录,记录总共有一条,T4时刻事务2向数据库中插入一条记录,T6时刻事务2提交事务。T7事务1再次查询数据数据时,记录变成两条了。这种情况是"虚读(phantom read)"。

4. 不可重复读(unrepeated read):一个事务两次读取同一行数据,结果得到不同状态结果,如中间正好另一个事务更新了该数据,两次结果相异,不可信任。

 事务1事务21开启事务 2 开启事务3查询数据,age=20 4 查询数据,age=205 更新数据,age=306 提交事务7查询数据,age=30 8  9  

 

在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,此时age=20,T4时刻事务2查询同一条数据,T5事务2更新数据age=30,T6时刻事务2提交事务,T7事务1查询同一条数据,发现数据与第一次不一致。这种情况就是"不可重复读(unrepeated read)"。

5. 第二类丢失更新(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失。

 事务1事务21开启事务 2 开启事务3更新数据,age=25 4  5 更新数据,age=306提交事务 7 提交事务

 

在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1更新数据age=25,T5时刻事务2更新数据age=30,T6时刻提交事务,T7时刻事务2提交事务,把事务1的更新覆盖了。这种情况就是"第二类丢失更新(second lost updates)"。

 

数据库事务隔离级别

隔离级别是否出现第一类丢失更新是否出现脏读是否出现虚读是否出现不可重复读是否出现第二类丢失更新Serializable否否否否否Repeatable Read否否是否否Read Commited否否是是是Read Uncommited否是是是是

 

数据库的事务隔离级别越高,越能解决并发中可能出现的问题。但是处理并发的能力就越弱。

也就是说,如果数据库事务采用serializable级别的隔离级别,就不会发生并发的问题。但处理数据的能力非常弱。大部分数据库都采用的是read commited隔离级别。

那怎么来解决并发中可能出现的问题呢?需要用到数据库锁。悲观锁和乐观锁。

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

一个典型的悲观锁的调用:select * from users where name=’leo’ for update.

 取款事务存款事务1开始事务 2 开始事务3select * from accounts where id=1 for update; 查询结果显示存款余额为1000元,这条记录被锁定 4 select * from accounts where id=1 for update;执行该语句时,事务停下来等待取款事务解除对这条记录的锁定。5取出100元。把存款余额改为900元。 6提交事务 7 事务回复运行,查询结果显示存款余额为900元。这条记录被锁定。8 汇入100元,把存款余额改为1000元。9 提交事务

 

使用乐观锁时,可以在表中添加一个字段:version。

但读数据时,连同version一同读出。在update时,将version+1,然后与数据库中的version比较。如果大于数据库中的版本,执行update。如果等于或小于数据库中的version,那么就是脏数据。不执行。

转载于:https://www.cnblogs.com/leiwei/p/3685470.html


最新回复(0)