美文网首页5分钟软件工艺精解
[5分钟讲解]数据库并发问题和解决思路

[5分钟讲解]数据库并发问题和解决思路

作者: Alchemist | 来源:发表于2019-03-22 19:17 被阅读0次

    前置知识

    数据库事务:是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。refer

    事务的四大基本要素:ACID refer

    划重点:
    在ACID四大要素中,Isolation要素确定了其他用户和系统对事务完整性的可见性。而事务的并发所带来的问题往往与Isolation要素的执行情况有关。

    事务并发可能带来的问题

    • 脏读(dirty read)(w-w conflict): A事务修改数据并回滚,但在回滚之前数据已经被B事务读取
    • 不可重复读(R-W-R conflict): 在一个事务过程中,前后两次读到的数据不一致(被中途被其他事务修改)
    • 丢失提交(lost update problem, W-W conflict): 两个事务同时对一个数据进行读写操作(e.g. 取出数据并+1),可能导致其中一个事务的写操作未达到预期效果,像是丢失一样。
    • 幻读(incorrect summary problem):A事务修改所有数据行之后,B事务插入新数据,A再查询总行数。

    如何解决

    方案1: 设置数据库级别

    划重点:
    为了解决事务并发引起的问题,SQL标准定义了4个事务隔离级别作为数据库层面的标准: refer

    • Read Uncommitted
    • Read Committed
    • Repeatable Read
    • Serializable


      image.png

    事务隔离级别在各个数据库的实现方式不同,但都符合SQL的标准。
    以MySql为例,默认的事务隔离级别为:Repeatable Read。

    通过设置事务隔离级别,可以解决事务并发带来的问题。但在实际应用中并不一定是最好的解决办法,因为:

    1. 隔离级别越高,并发性能越低。
    2. 数据库事务隔离级别的设置是全局设置,会影响整个数据库并发性能。


      image.png

    方案2: 对数据(表或行)加锁

    前置知识
    • 乐观锁和悲观锁 refer
      数据库事务隔离级别的实现本质还是锁机制,只是数据库可以根据隔离级别的设置来隐式的加解锁。
    数据库层面的显式悲观锁

    除了设置数据库事务隔离级别之外(隐式的加解锁),我们还可以在执行某些事务的过程中通过“显式加锁“来解决并发问题。
    以MySql为例:refer

    • 如果读取出来的结果集需要修改后再提交,需使用select ... for update读取结果集。(用于解决“丢失提交”的问题)
    • 当有关联关系的两个实体可能同时新增时,一方因新增实体修改关联关系,需使用select ... in share mode查询另一方数据进行关联关系的更新。

    以上两种加锁方式,本质上都是数据库层面的悲观锁实现。

    应用层面的乐观锁

    乐观锁的实现需要配合数据库的update语句来实现。在进行update这个原子操作的同时进行version或timestamp的验证。如果发现版本已更新,则回退。

    Note: Mysql数据库的Update语句中嵌套子查询(查询其他表)的情况下下,不会锁子查询涉及的表。所以,在有查A表版本,更新B表这样的操作时,只能通过select ..for update这样的悲观锁将A表的数据进行锁定。
    A locking read clause in an outer statement does not lock the rows of a table in a nested subquery unless a locking read clause is also specified in the subquery. refer

    应用层面的悲观锁

    如果有多个分布式的应用需要与数据库产生并发操作,那么我们可以引入一个第三方协调服务来处理并发问题,其本质还是一种悲观锁的实现。
    例如: 基于zookeeper的分布式锁

    相关文章

      网友评论

        本文标题:[5分钟讲解]数据库并发问题和解决思路

        本文链接:https://www.haomeiwen.com/subject/knkqvqtx.html