1. 事务特性和事务的隔离级别

        数据库部分,我开篇就进入事务部分的讨论。由于我以为这块是数据库比较核心重要的内容。sql

        大学学过数据库原理的,基本上都能脱口说出数据库的四大特性:ACID。但是真正深刻理解了吗?咱们再来从新看一下这四大特性:数据库

  •  原子性( Atomicity ):一个事务中是包含多个CRUD操做的,所以事务的第一个要求就是,这些操做应该所有成功或所有失败,怎么保证呢?很简单,执行过程当中有异常,回滚操做便可。生活中常见的转帐场景,A给B转300块钱,假设在同一个数据库操做,第一条sql:A的帐户减去300,第二条sql:B的帐户增长300,两个sql同时成功转帐成功,同时失败转帐失败;
  • 一致性( Consistency ):对于一致性,我是这么理解的:就是事务前和事务后,数据库是从一个正确状态变动到了另外一个正确状态,不然事务回滚。怎么解释这句话呢?咱们还用上面转帐的例子,若是A的帐户里只有280块钱了,没有任何限制的状况下数据库是能执行成功的,执行后的结果是A帐户余额-20,但是咱们都知道这在业务上是不容许的,也就是说若是这样操做数据库就从以前的正确状态变动到了一个错误的状态上来。为保证一致性, A的帐户余额>=300的时候,咱们才能容许成功。保障一致性我目前想到两个方法,一是数据库保证,事务执行后,经过数据库机制来检测是否状态都正确(触发器),二是经过应用程序保证,这个就简单了,应用层增长业务校验便可。
  • 隔离性( Isolation ):隔离性是说多个事务执行的时候是互不干扰的,本身执行本身的,谁也没法看到其余事务的数据。可是这里就会引起好多问题了,若是Java里多线程带来的复杂性同样,这里后面会展开讨论。
  • 持久性( Durability ):一个事务完成后,执行结果是要持久化保存的。其实这里就是要求必须进行数据库的commit操做,数据库的commit就是从回退段中永久性的写入数据表空间的操做。

        同时知足以上四个特性时,才是一个完整的事务。再进一步思考一种这样的状况 ,大量的并发状况下,有两个这样的事务,事务T1中是这样的语句:多线程

        1. select state from A where id=1; 并发

        2. update B set  status = '0' where id=1;性能

        事务T2中是这样的语句:
        3. update A set state='1' where id=1; spa

        4. select status from B where id=1;线程

        已知当前 A表中id=1的 state='0',B表中id=1的status='1',若是两个事务是并发执行的,那么语句1的select查到的结果是什么?语句4select查到的结果是什么?答案是不知道,由于咱们不知道语句1先执行仍是语句3先执行,2和4同理。那么有没有办法控制呢?有,那就是引入事务的隔离级别。这也是咱们大学学过的内容。先说说四个隔离级别吧:事务

  • 读未提交(read uncommited):事务能够读到其余事务已修改未提交的数据。这种隔离级别下,若是语句在时间顺序上执行的是 一、3,那么1的结果就是state='0',若是顺序是三、1,那么1的结果就是state='1';若是读到了事务T2未提交的数据,而T2又由于执行错误回滚,事务T1读到的数据就是脏数据,这种状况称为脏读。
  • 读已提交(read commited):事务读到的都是其余事务已提交过的数据。这种隔离级别下,若是语句1执行时,T2未提交,则语句1读到state='0',若是T2提交则读到state='1',不会读到未提交的数据了。可是,新的问题来了,若是T1中有又增长了语句5,语句5跟语句1同样,那么1和5的结果可能不同吗?答案是有这种几率。若是 执行时间顺序是这样的,1 ,事务T2提交,5,这样1和5读到的数据就不一致了,同一个事务中同一条语句读到了不一样的数据?这种状况就称之为不可重复读。有办法解决吗?有!就是语句1读取的时候,把读到的数据加锁,不容许再修改,直至事务提交或回滚再释放锁。
  • 可重复读(read repeatable):事务内部对数据的读取先后是一致的。这种隔离级别解决了不可重复读的状况,实现方案前面也提到了,就是加锁。可是还有一种状况,你是锁不住的,那就是T2中有insert怎么办?语句1的where 条件去掉,这样语句1 就是查询全部数据了,这时候把读出来的数据都锁住,别的事务不容许操做,但这时候T2给A表新增了一条数据,并在事务T1提交前提交的。事务T1觉得处理了全部的A表数据,但发现多出来一条其余数据。这种状况称为幻读
  • 串行读( Serializable):彻底串行化读,使用表级锁,读和写都会阻塞。这种状况下,数据库的并不是能力受限、性能不高,但数据的正确性有保障。

        总结下事务的隔离,咱们整理出下表:ci

隔离级别 脏读(Dirty Read) 不可重复读(NonRepeatable Read) 幻读(Phantom Read)
未提交读(Read uncommitted) 可能 可能 可能
已提交读(Read committed) 不可能 可能 可能
可重复读(Repeatable read) 不可能 不可能 可能
可串行化(Serializable ) 不可能 不可能 不可能
相关文章
相关标签/搜索