今天是工做日的最后一天,明天就是除夕了,赶忙趁这个时间再写一篇文章。今天主要说一下事务,这里主要探讨数据库的事务机制,并非spring的事务,毕竟大多数人对spring的事务实际上是很清楚的。可是对于数据库底层的事务了解的不是很深刻,每每有时候会遇到奇怪的现象,废话很少说,直接开始!mysql
--------------------------------------------------华丽的分割线--------------------------------------------spring
首先事务有四个特性(ACID):原子性,一致性,隔离性,持久性。这些特性能够保证多个数据库事务并发执行时互不干扰,不会取到中间状态的错误结果。通常的数据库会给咱们设置多个事务隔离级别:Read uncommitted,Read committed,Repeatable read,Serializable。多个事务并发执行,若是说要保证操做一个接一个执行,那么就要保证串行化,这个隔离级别是Serializable,通常来讲咱们不多选择这个事务隔离级别,并发量太差。咱们通常能够采用锁机制来实现,采用行锁或者表锁来完成。上面提到的都是写事务,其实事务准确的来讲应该分为:读事务和写事务。在大多数业务当中,读事务的比例是远高于写事务比例的,比例大概为10:1,为了提升读事务的性能,数据库通常采用COW(写时复制),MVCC(多版本控制机制)来防止写事务阻塞读事务。sql
关于数据库并发的解决方案主要有如下几种:数据库
一、锁并发
若是两个事务操做不一样的行,那么是行锁级别的话就能够互相不干扰;若是其中一个事务锁行,另外一个事务锁表,那么就会致使其中一个等待;若是一个事务A执行须要先锁A而后请求B锁,另外一个事务锁B而后请求A锁,就会产生死锁,这个通常设置一下事务超时时间就能够解决。性能
二、COW版本控制
写时复制其实很是常见,好比说JUC包下的copyonwritearraylist。原理就是当写的时候不是直接在原数据上写,而是复制一份新数据,在新数据上修改,而后原子的更换叶子指针的地址。当此时有读操做的时候,若是读操做在原子更换前,那么读的是旧数据,若是在更换后,那么获取的是新数据。这样就保证了读和写的同时进行。指针
三、MVCC事务
多版本控制能够说是最难掌握的,而且也是比较复杂的一种机制,mysql的innodb就比较经常使用这种机制。it
先来看一个图:
其实在存储数据的时候,会有两个隐藏列,一个是数据更新时间,一个是数据删除时间,固然这里的时间都是版本号。当你开一个事务的时候,数据库首先会给你一个自增的版本号,而后你带着这个版本号就捞取数据。那么会产生这么一个规则:
(1)在select的时候,会捞取(数据修改版本号<=当前事务版本号)而且(删除版本号没有或者删除版本号大于当前事务版本号)的行。
(2)insert操做致使update版本号为当前事务版本号。
(3)update操做会首先复制一行而后修改,而且设置update版本号为当前事务版本号。
(4)delete操做会致使delete版本号为为当前事务版本号,这里只作一下标记。
因为MVCC存储了一个数据的多个版本,因此会按期删除再也不须要的版本,及时回收空间。
对于上面的说明,举一个例子:
假设mysql数据库的隔离级别为默认的(4:可重复读),那么必须保证一个事务的操做不会致使另外一个事务先后两次读取的数据不一致。
那么MVCC机制如何解决这个问题?
首先假设第一个事务第一次读取数据,此时第二个事务修改了第一个事务要读取的数据,那么这时候会产生新的一行,而且将其版本号设置为最新的,那么第一个事务再一次读取数据的时候由于遵循了MVCC机制(扫描修改版本号小于等于当前事务版本号的行),就能够保证两次读取的数据一致。
以上就是本章的介绍,顺便祝你们新年快乐。