数据库的事务

今天是工作日的最后一天,明天就是除夕了,赶紧趁这个时间再写一篇文章。今天主要说一下事务,这里主要探讨数据库的事务机制,并不是spring的事务,毕竟大多数人对spring的事务其实是很清楚的。但是对于数据库底层的事务了解的不是很深入,往往有时候会遇到奇怪的现象,废话不多说,直接开始!

--------------------------------------------------华丽的分割线--------------------------------------------

首先事务有四个特性(ACID):原子性,一致性,隔离性,持久性。这些特性可以保证多个数据库事务并发执行时互不干扰,不会取到中间状态的错误结果。一般的数据库会给我们设置多个事务隔离级别:Read uncommitted,Read committed,Repeatable read,Serializable。多个事务并发执行,如果说要保证操作一个接一个执行,那么就要保证串行化,这个隔离级别是Serializable,一般来说我们很少选择这个事务隔离级别,并发量太差。我们一般可以采用锁机制来实现,采用行锁或者表锁来完成。上面提到的都是写事务,其实事务准确的来说应该分为:读事务和写事务。在大多数业务当中,读事务的比例是远高于写事务比例的,比例大概为10:1,为了提高读事务的性能,数据库一般采用COW(写时复制),MVCC(多版本控制机制)来防止写事务阻塞读事务。

关于数据库并发的解决方案主要有以下几种:

1、锁

如果两个事务操作不同的行,那么是行锁级别的话就可以互相不干扰;如果其中一个事务锁行,另一个事务锁表,那么就会导致其中一个等待;如果一个事务A执行需要先锁A然后请求B锁,另一个事务锁B然后请求A锁,就会产生死锁,这个一般设置一下事务超时时间就可以解决。

2、COW

写时复制其实非常常见,比如说JUC包下的copyonwritearraylist。原理就是当写的时候不是直接在原数据上写,而是复制一份新数据,在新数据上修改,然后原子的更换叶子指针的地址。当此时有读操作的时候,如果读操作在原子更换前,那么读的是旧数据,如果在更换后,那么获取的是新数据。这样就保证了读和写的同时进行。

3、MVCC

多版本控制可以说是最难掌握的,并且也是比较复杂的一种机制,mysql的innodb就比较常用这种机制。

先来看一个图:115120_NQoQ_3203060.png

其实在存储数据的时候,会有两个隐藏列,一个是数据更新时间,一个是数据删除时间,当然这里的时间都是版本号。当你开一个事务的时候,数据库首先会给你一个自增的版本号,然后你带着这个版本号就捞取数据。那么会产生这么一个规则:

(1)在select的时候,会捞取(数据修改版本号<=当前事务版本号)并且(删除版本号没有或者删除版本号大于当前事务版本号)的行。

(2)insert操作导致update版本号为当前事务版本号。

(3)update操作会首先复制一行然后修改,并且设置update版本号为当前事务版本号。

(4)delete操作会导致delete版本号为为当前事务版本号,这里只做一下标记。

由于MVCC存储了一个数据的多个版本,所以会定期删除不再需要的版本,及时回收空间。

 

对于上面的说明,举一个例子:

假设mysql数据库的隔离级别为默认的(4:可重复读),那么必须保证一个事务的操作不会导致另一个事务前后两次读取的数据不一致。

那么MVCC机制如何解决这个问题?

120445_IK4m_3203060.png

首先假设第一个事务第一次读取数据,此时第二个事务修改了第一个事务要读取的数据,那么这时候会产生新的一行,并且将其版本号设置为最新的,那么第一个事务再一次读取数据的时候因为遵循了MVCC机制(扫描修改版本号小于等于当前事务版本号的行),就可以保证两次读取的数据一致。

以上就是本章的介绍,顺便祝大家新年快乐。

 

 

转载于:https://my.oschina.net/u/3203060/blog/830408

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值