原子操作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
维基百科