acid

  1. 云栖社区>
  2. 博客>
  3. 正文

acid

广贤 2012-08-31 10:08:00 浏览757
展开阅读全文

ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库系统,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。

  原子性
  整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  一致性
  在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
  隔离性
  两个事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。
  持久性
  在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
  由于一项操作通常会包含许多子操作,而这些子操作可能会因为硬件的损坏或其他因素产生问题,要正确实现ACID并不容易。ACID建议数据库将所有需要更新 以及修改的资料一次操作完毕,但实际上并不可行。
  目前主要有两种方式实现ACID:第一种是Write ahead logging,也就是日志式的方式。第二种是Shadow paging。

回滚

 删除由一个或多个部分完成的事务执行的更新。为在应用程序、数据库或系统错误后还原数据库的完整性,需要使用回滚。
  回滚泛指程序更新失败, 返回上一次正确状态的行为。
  回滚对程序员意味着非常严重的失误。因为回滚次数往往与程序员的薪金直接联系。主流互联网公司通常都将回滚定位为最严重的事故。
  回滚与恢复有本质的区别。
  而升级回滚则是指因升级中所发生的意外而自动回滚

1        事务并发处理(面试的意义更大)

a)  事务:ACID

         i.   Atomic ConsistencyItegrity Durability

b)  事务并发时可能出现的问题:

第一类丢失更新(Lost Update)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元

 

T4

 

查询账户余额为1000元

T5

 

汇入100元把余额改为1100元

T6

 

提交事务

T7

取出100元把余额改为900 元

 

T8

撤销事务

 

T9

余额恢复为1000元(丢失更新)

 

   

    dirtyread脏读(读到了另一个事务在处理中还未提交的数据)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

 

查询账户余额为1000元

T4

 

汇入100元把余额改为1100元

T5

查询账户余额为1100元(读取脏数据)

 

T6

 

回滚

T7

取款1100

 

T8

提交事务失败

 

 

    non-repeatableread 不可重复读

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元

 

T5

 

汇入100元把余额改为1100元

T5

 

提交事务

T6

查询帐户余额为1100元

 

T8

提交事务

 

 

    secondlost update problem 第二类丢失更新(不可重复读的特殊情况)

时间

取款事务A

存款事务B

T1

 

开始事务

T2

开始事务

 

T3

 

查询账户余额为1000元

T4

查询账户余额为1000元

 

T5

 

取出100元把余额改为900元

T6

 

提交事务

T7

汇入100元

 

T8

提交事务

 

T9

把余额改为1100元(丢失更新)

 

 

    phantomread 幻读

时间

查询学生事务A

插入新学生事务B

T1

开始事务

 

T2

 

开始事务

T3

查询学生为10人

 

T4

 

插入1个学生

T5

查询学生为11人

 

T6

 

提交事务

T7

提交事务

 

c)  数据库的事务隔离机制

        i.   查看 java.sql.Connection 文档

       ii.   1:read-uncommitted  2:read-committed  4:repeatable read  8:serializable(数字代表对应值)

为什么取值要使用 1 2 4 8而不是 1 2 3 4

1=0000  2=0010 4=01008=1000(位移计算效率高)

1.     只要数据库支持事务,就不可能出现第一类丢失更新

2.     read-uncommitted(允许读取未提交的数据) 会出现dirty read, phantom-read,

non-repeatableread 问题

3.     read-commited(读取已提交的数据项目中一般都使用这个)不会出现dirty read,因为只有另

一个事务提交才会读出来结果,但仍然会出现 non-repeatable read 和 phantom-read

   使用read-commited机制可用悲观锁乐观锁来解决non-repeatable read phantom-read问题

4.     repeatableread(事务执行中其他事务无法执行修改或插入操作    较安全)

5.     serializable解决一切问题(顺序执行事务不并发,实际中很少用)

d)  设定hibernate的事务隔离级别(使用hibernate.connection.isolation配置取值1、2、4、8)

        i.   hibernate.connection.isolation= 2(如果不设 默认依赖数据库本身的级别

       ii.   用悲观锁解决repeatable read的问题(依赖于数据库的锁)

(详见项目 hibernate_3100_Hibernate_Concurrency_Pessimistic_Lock)

1.     select ... for update

2.      使用另一种load方法--load(xx.class , i , LockMode.Upgrade)

a) LockMode.None无锁的机制,Transaction结束时,切换到此模式

b) LockMode.read在査询的时候hibernate会自动获取锁

c) LockMode.write insert  updatehibernate 会自动获取锁

d) 以上3种锁的模式,是hibernate内部使用的(不需要设)

e) LockMode.UPGRADE_NOWAIT是 ORACLE 支持的锁的方式

e)  Hibernate(JPA)乐观锁定(ReadCommitted)

(详见项目hibernate_3200_Hibernate_Concurrency_Optimistic_Lock)

实体类中增加version属性(数据库也会对应生成该字段,初始值为0),并在其get方法前加

@Version注解,则在操作过程中没更新一次该行数据则version值加1,即可在事务提交前判断该数据是否被其他事务修改过.

            @Version

时间

转账事务A

取款事务B

T1

 

开始事务

T2

开始事务

 

T3

查询学生为10人

查询账户余额为1000 version=0

T4

查询账户余额为1000 version=0

 

T5

 

取出100 把余额改为900 version=1

T6

 

提交事务

T7

汇入100元

 

T8

提交事务 ? version>0

throw Exception

 

T9

把余额改为1100元(丢失更新)

 

 


网友评论

登录后评论
0/500
评论
广贤
+ 关注