事务具有4个属性:原子性、一致性、隔离性、持久性

事务是指对系统进行的一组操作,为了保证系统的完整性,事务需要具有ACID特性,具体如下:
1. 原子性(Atomic)
     一个事务包含多个操作,这些操作要么全部执行,要么全都不执行。实现事务的原子性,要支持回滚操作,在某个操作失败后,回滚到事务执行之前的状态。
     回滚实际上是一个比较高层抽象的概念,大多数DB在实现事务时,是在事务操作的数据快照上进行的(比如,MVCC),并不修改实际的数据,如果有错并不会提交,所以很自然的支持回滚。
     而在其他支持简单事务的系统中,不会在快照上更新,而直接操作实际数据。可以先预演一边所有要执行的操作,如果失败则这些操作不会被执行,通过这种方式很简单的实现了原子性。
2. 一致性(Consistency)
     一致性是指事务使得系统从一个一致的状态转换到另一个一致状态。事务的一致性决定了一个系统设计和实现的复杂度。事务可以不同程度的一致性,事务结束后系统状态是一致的;
3. 隔离性(Isolation)
     并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。在事务并发操作时,可能出现的问题有:
    脏读:事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
     不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这会导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。
    幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。
     事务的隔离级别从低到高有:
    Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
     Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题但是,会发生幻读的问题,因为RC级别的事务隔离,依靠数据库的X锁(exclusive lock)对写加锁,和S锁(share lock)来实现的,X锁和S锁是互斥的,对记录上了S锁就不能上X锁(获得X锁是修改的前提),保证数据的正确性。但是,RC级别下,单个查询结束立即释放S锁,会被其他人给修改数据

     Repeated Read:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、重复读。RR级别,在RC的基础上,在左边的事务全程加S锁,解决了重复读问题。
     Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题
     通常,在工程实践中,为了性能的考虑会对隔离性进行折中。
4. 持久性(Durability)
     事务提交后,对系统的影响是永久的。即,事务完成后,数据提交到了数据库或者磁盘。


ps:原子性VS一致性
  举个栗子,比如转账的例子,A账户-100,B账户+100
  原子性和一致性:原子性是选择A-100和B+100是不是一个整体,一致性是是否加上B+100

Tips:
  一般数据库是read committed级别,但mysql是repeated read级别

MVCC的文章,参考 数据库村的旺财和小强 MVVC
posted @ 2016-12-21 22:26  Bug开发攻城狮  阅读(825)  评论(0编辑  收藏  举报