数据库事务,隔离级别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/about4years/article/details/77542136

数据库事务,隔离级别


事务的四个性质:

  • 原子性(Atomicity):要么都发生,要么都不发生。记录之前的版本,允许回滚。
  • 一致性(Consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态。
  • 隔离性(Isolation):不能让一个事务看到其他事务的中间状态。
  • 持久性(Durability):每一次的事务提交后持久化到数据库。

然而,通常来说,我们需要适当的牺牲隔离性这个属性,来换取并发度,这是必须的。当然这就带来了不同的数据库隔离级别以及并发控制的问题。


并发带来的问题:

  • Dirty Read(脏读):事务A进行的途中读到了事务B进行途中改变的某个字段
  • Unrepeatable Read(不可重复读):同一个事务读2次某个字段,不一致
  • Phantom Read(幻读):同一事务2次查,查出不同条数的记录

    脏读:
    事物之间是完全透明的,一个事务改变了某个字段但是还没有提交,其他事务就可以读到了这个字段的最新值。我们想象一个场景,事务A准备存钱,余额本来是1000块,刚要查的时候,事务B开始执行了,事务B取出了1000元,此时线程分配到了事务A,进行查询,查到了0块,此时事务B出现问题,回滚,余额又变成了1000,然后事务A存钱,改变余额的值:500,提交事务。最终余额变成了500,这显然是必须避免发生的。

    我们需要限定,一个事务提交前所改变的东西,对其他事务是不可见的,也就是只要你不提交,你所做出的改变别的事务是看不到的,别的事务读到的肯定是老数据。对应了数据库的隔离级别:READ_COMMITTED,这个级别的隔离不允许脏读的发生,而允许了后两者的发生。这也是大多数数据库的默认隔离级别,不过mysql不是。

    虽然上面这种隔离级别避免了脏读,随之而来的他也带来了一种新的问题:不可重复读,在一个事务的过程中读取同一个字段你可能得到不同的值,想要避免这种情况,对应的隔离级别就是REPEATABLE_READ,这是mysql的默认级别。

    幻读跟不可重复读很像,简单的可以理解为事务 A 读取了事务 B 已提交的新增数据。对应了SERIALIZABLE的隔离级别,这个隔离级别就完全是串行化了,将会极大的降低性能。


并发控制

  • 数据库锁。事务有读,写,读写混合事务,锁则分为2种:读锁和写锁。你可以锁住一行,也可以锁住一个数据块,或者是一张表。读锁可以同时加在同一个对象上,写锁则只能有一个。
    加锁所带来的不可避免的问题当然就是死锁,解决办法一般是设置一个过期时间,时间到了自动回滚该事务并且释放锁。
  • 写时复制。也就是所谓的copyOnWrite(就像java的copyOnWriteArraylist)。基于一个思想:读的概率会远大于写的概率。
  • MMVC。所谓的 多版本并发控制。对每一行数据维护多个版本,例如mysql的innodb引擎,他的机制是这样的:每当一个事务开始时,会被分配到一个版本号(递增),对于每一个查询语句,mysql会将查询到的行的版本号与事务版本号进行对比并结合其的隔离级别来决定是否返回该行。对于Insert语句,新插入的行被赋予这个事务的版本号。对于select语句,只有该行的修改版本号<=该事务的版本号,并且该行的删除版本号没被定义或者也小与该事务的版本号,对于mysql,innodb默认的数据库隔离级别,这些数据行是不能被返回回去的。对于Delete语句,该行会被设置为删除他的事务的版本号,update同理。

猜你喜欢

转载自blog.csdn.net/about4years/article/details/77542136
今日推荐