一、事务

概念

事务是一组满足ACID特征的操作,可以通过commit提交或者Rollback回滚

ACID

  • 原子性(Atomicity)
    • 这个地方的原子性和物理里面的原子性是一个道理,事务被认为是对数据库操作的最小单元,为什么这么说呢,为了数据库的信息安全性,我们规定事务要么整个成功要么整个失败,不可能是执行了半个事务,那样开发者就无法确定数据库中信息的状态
    • 回滚:事务在执行的过程中出现了错误可以进行回滚,有个东西叫做回滚日志,里面记录了事务所执行的修改操作,回滚的时候再反向执行这些操作
  • 一致性:数据在事务执行前后都保持一致性状态,在一致性状态下,所有事务对一个数据的读取结果都是相同的
  • 隔离性:一个事务所做的修改在最终提交前,对其他事务是不可见的。
  • 持久性:
    • 一旦事务提交,则其所作的修改将会永远保存到数据库中,即使系统发生崩溃,事务执行的结果也不能丢失,使用重做日志来保证持久性。
    • 事务之所以有这么个性质就是为了能营地数据库崩溃的情况

      AUTOCOMMIT

      MySQL默认采用自动提交模式,如果不是显式使用start transaction语句来开始一个事务的话,每个查询都会被当做一个事务来自动提交;这会导致一个问题,用别的数据库的时候操作完成后也没有提交的习惯,需要注意的

      二、并发一致性问题(数据库面临的主要问题)

      在没有并发的情况下,事务串行执行,原子性是在任何情况下都能保证的,这时候也不存在隔离性的问题,所以数据的一致性就能得到保证。

但是在并发的环境下,事务的隔离性就很难保证,因此会出现很多并发一致性问题

丢失修改

t1和t2两个事务都对一个数据进行修改,t1先改,t2后改,t2的修改覆盖了t1的修改,比如ab两个售票点读取出了航班的余票是16,a卖了一张修改数据库余票-1为15,b也卖了一张修改数据库余票-1为15,这个时候就出问题了

读脏数据

T1修改了一个数据,T2去读取了这个数据,T1回滚了这次修改,T2读到的数据是假数据

不可重复读

T1读取了一个数据,T2修改了这个数据,当T1再次去读这个数据的时候读取的结果第一次不一样

幻影读

T1读取了某个范围的数据,T2在这个范围内插入了新的数据,T1再次去读这个范围的数据,发现和第一次读取的数据不同

不难发现所有问题的产生主要因为事务的隔离性被破坏了,一个事务在操作的过程中另一个事务,解决方法是通过并发控制来保证隔离性,这类似于线程锁,要是让用户来实现会相当麻烦,数据库管理系统提供了事务的隔离级别,其实就是实现了不同程度的安全锁,让用户能直观的去选择一种实现方案来解决问题

三、封锁(事务隔离级别的实现原理)

封锁粒度

MySQL来说提供了两种封锁粒度:行级锁、表级锁

这个和线程锁的思想差不多,不过数据库对效率的要求更高

尽量只锁定需要修改的那个部分(或者对修改会造成影响的部分),锁定的数据越少,发生锁争用的可能也就越小,系统的并发程度就越高

另一方面,锁定的资源越精确,那很可能需要的锁的数量就越多,而锁的各种操作(获取、检查状态、释放)都会增加系统的开销。所以精确度越高那系统开销就越大

结合着两个点来说,在选择的时候要根据服务器的性能来做权衡

封锁类型

  • 读写锁:简单解释一下
    • 读锁:一个事务对数据的对象(可能是行可能是表,看决策是怎么做的)加了读锁之后,就可以对它进行读取了,此时别的事务最多只能对这个对象加读锁,也就是最多只能看看,不可能再修改了
    • 写锁:一个事务对数据对象加了写锁之后,别的事务就不能再对它加任何锁了,也就是不能读写,这个时候一旦读写就可能出问题嘛