一、什么是事务
事务简单的来说就是把对数据库的一系列操作放到一个可控制的过程中,进行可量化的控制,事务有4个必须的属性原则:
1、原子性:必须保证在一个事务中的操作要么全部执行,要么全部不执行。
2、一致性:事务操作在完成时必须使数据库保持一致的状态,内部数据结构必须是完整的。比如一个例子 A和B都有50块钱,他们两个无论怎么进行相互转账,A+B始终是100。
3、隔离性:简单的来说就是各个事务之间的影响程度。
4、持久性:不管数据库是否发生问题,事务在完成之后数据应该永远的保存在数据库中
二、针对事务的隔离性引发的问题
事务之间是会相互影响的,这时候需要有一个规则来约束事务操作,于是有了事务隔离。
事务隔离分为4种 : 由低到高依次为Read uncommitted(读未提交)、Read committed(读提交)、Repeatable read(重复读)、Serializable(序列化,也叫串行化),这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。
注:Sql Server 、Oracle事务隔离级别默认是Read committed(读提交),MySQL的默认隔离级别就是Repeatable read(重复读)
假设数据库事务隔离级别为以下4种依次举例:
1、Read uncommitted(读未提交):A进行了一条数据操作,但是没有提交事务,这时候如果B进行这条数据查询,是可以查到A的数据操作的,但是这时候A还没有提交事务,如果A不提交或者进行了事务回滚,那么B查询到的数据就是脏数据。
2、Read committed(读提交):A正在进行数据操作,还没有提交事务,B这个时候也去查询了A操作的这个数据,并且修改了,马上提交了事务,这时候A再去提交事务的时候会发现数据不对了,因为A手上的数据是B没修改之前的,现在去提交时,数据库的数据已经变成B更改之后的了,这种场景发生在金钱上会有很大问题,明明卡上有钱的A去消费,结果B抢在A前面消费完了,这时候A就是没法付账了。这就是不可重复读。
3、Repeatable read(重复读):这种情况只会发生在有一个事务在新增操作,比如A在查自己的银行卡现在是100块钱,A表示看花了,想再查一次,这时候有个人在给他转账,然后A第二次查询,查出了1000块了,又不敢相信自己是不是看花了。这就是幻读。
4、Serializable(序列化,也叫串行化):Serializable是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。
事务隔离级别参考了一个哥们的博客http://blog.csdn.net/fg2006/article/details/6937413
三、数据库锁(这里只说几种常见的锁,不怎么用的锁我不知道、也不研究,需要的自行问度娘)
乐观锁与悲观锁就是一个操作数据的姿势问题,乐观心态与悲观心态
1、乐观锁:每次去找数据库拿数据都认为别人不会对数据做什么更改,所以不会上锁。但是在找数据库要数据的时候会带一个数据版本过来,做更新的时候会去把拿到的这个版本与数据库现在的要修改的数据版本做对比 只有大于或者等于数据库中的数据版本,那么它就认为这次操作是对的,可以执行。否则就不执行。
2、悲观锁(for update):每次去找数据库拿数据都认为别人会改,所以它在查询的时候就给数据加锁,其他人只能查询数据不能对数据做修改,只能等加锁的人操作完成之后才会释放锁。
乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
3、共享锁:又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改
4、排它锁:又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。