数据库之ACID

"1.原子性2.一致性3.隔离性4.持久性 "

Posted by 青乡 on January 1, 2016

原子操作Automic

只有两种可能:
1.提交
2.回滚

单条sql语句的事务和多条sql语句的事务,都是只有两种情况。

所有数据一致性Consistency

银行总共300,ABC各100。
无论怎么转账操作,总的数据都是300。

单个数据隔离性Isolation

4种情况

A有100。
两个事务T1T2(在代码service层,每个事务内部包含两个SQL操作)并发执行写读数据A100,T1或T2的两个SQL会产生以下四种情况:
1.两次读的数据不一样,假设第二次读了未提交成功的数据
这种情况最严重,因为读了错误的数据。
2.两次读的数据不一样,假设第二次读已提交成功的数据
这种情况比1要好,虽然两次读的数据不一样,但是读的数据没有错误。
3.两次读的数据一样,但是没有解决范围数据不一致的问题
加独占行锁,解决两次读数据不一样的问题。
4.顺序读
加范围锁/表锁,解决范围数据不一致的问题。

如何解决

1.脏读
没加锁,事务A第二次读未提交数据。

2.幻读
加锁,只在事务B写的时候加锁。
事务B写的时候加锁(独占锁,不允许其他事务写读),确保事务A第二次读的数据是事务B已提交的数据。
3.重复读(两次读的数据一样)
事务A一直加行锁(独占锁,不允许其他事务写读),确保事务A两次读的同一条数据(行数据)一样。

4.顺序读
所有的事务,都按顺序执行,不会交叉执行导致数据不一致的问题。 事务A一直加范围锁/表锁(独占锁,不允许其他事务写读),确保事务A两次的整张表的数据一样。

隔离性与一致性的关系

隔离性的问题会导致读的数据不正确,从而导致写数据不正确,最终数据库的总数据不正确,所以会带来一致性问题。

总结

1.前面3种都有数据不一致的问题,不同情况下的数据不一致。 每一种解决的问题,也是前面一种存在的数据不一致的问题。 但是,最终还是都有可能导致数据不一致。

2.怎么解决?第四种方法。但是却带来了性能问题。这是一个鱼和熊掌不可兼得的问题。此消彼长。

3.所以,从上往下是越来越安全,但是并发性能越来越低。

持久化到数据库Duration

保存到关系数据库。

其他

事务

数据库层
1.单条SQL
2.多条SQL
不管几条SQL,必须commit提交,才会最终生效。否则,只是暂时生效(正因为会暂时生效,才导致了会出现前面说的读未提交数据的情况),回滚之后,数据修改就失效。


代码service层
几条SQL
1.一条SQL
2.多条SQL

如何使用
spring注解-事务注解。

实现原理
1.底层还是基于数据库提供的事务功能。
2.代码dao层一般包含一条SQL。
3.持久层框架mybatis,会根据是否异常来决定是提交commit还是回滚rollback。

按行/表分类
1.行级锁
where id=’10’; //操作某一行的数据
2.表级锁
where id in(1,10); //操作范围/整张表的数据

按共享/排他分类

1.共享锁
其他事务可以读不能写。

2.独占/排它锁
不同事务互相排斥。
一个事务在更新数据的时候,另外一个事务既不能读更不能写。

提交commit

区别
1.更新数据
当前sql只是暂时更新了数据库里的数据。其他sql查询数据库的时候,发现数据已经改变。

2.提交数据
永久更新数据库里的数据。这就是ACID里的duration持久性。


作用
提交的作用就是永久的把数据写到数据库里。
如果没提交,只是暂时修改,因为未提交的数据可能回滚。

oracle隔离级别

默认读已提交

mysql隔离级别

默认可重复读

参考

http://www.hollischuang.com/archives/943

http://www.hollischuang.com/archives/900

http://comedsh.iteye.com/blog/698733

维基百科