• 数据库事务


    数据库的事务隔离级别:

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

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

    各种并发问题

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

      事务1 事务2
    1 开启事务  
    2   开启事务
    3 取出数据 age=20  
    4   取出数据 age=20
    5 更新数据 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 事务2
    1 开启事务  
    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 事务2
    1 开启事务  
    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 事务2
    1 开启事务  
    2   开启事务
    3 查询数据,age=20  
    4   查询数据,age=20
    5   更新数据,age=30
    6   提交事务
    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 事务2
    1 开启事务  
    2   开启事务
    3 更新数据,age=25  
    4    
    5   更新数据,age=30
    6 提交事务  
    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   开始事务
    3 select * 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,那么就是脏数据。不执行。

  • 相关阅读:
    Medium | LeetCode 148. 排序链表 | 归并排序(递归)
    Hard | LeetCode 4. 寻找两个正序数组的中位数 | 二分法
    Medium | LeetCode 341. 扁平化嵌套列表迭代器 | 递归 | 栈
    Hard | LeetCode 312. 戳气球 | 递归+记忆化数组 | 动态规划
    如何删除万能输入法
    javaweb 怎么获取路径
    Controller 返回 json那些小事
    螺旋矩阵
    javaweb怎么使用html
    tomcat中文乱码
  • 原文地址:https://www.cnblogs.com/leiwei/p/3685470.html
Copyright © 2020-2023  润新知