数据库事务与锁步骤数据库事务与锁步骤
什么是事务(Transaction)?
是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么 完全地不执行。 事务处理可以确保除非事务性单
元内的所有操作都成功完成,否则不会更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单
元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔
离性和持久性)属性。事务是数据库运行中的一个逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
举个例子加深一下理解:同一个银行转账,A转1000块钱给B,这里存在两个操作,一个是A账户扣款1000元,两一个操
作是B账户增加1000元,两者构成了转账这个事务。
两个操作都成功,A账户扣款1000元,B账户增加1000元,事务成功 两个操作都失败,A账户和B账户金额都没变,事务
失败
后思考一下,怎么样会出现A账户扣款1000元,B账户金额不变?如果你是把两个操作放在一个事务里面,并且是数据库
提供的内在事务支持,那不会有问题,但是开发人员把两个操作放在两个事务里面,而第二个事务失败会出现中间状态。现实
中自己实现的分布式事务处理不当也会出现中间状态,这并不是事务的错,事务本身是规定不会出现中间状态,是事务实现者
做出来的方案有问题。
事务的4个特性
原子性(Atomic):事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联
的操作具有共同的目标,并且是相互依赖的。如果系统只执行这些操作的一个子集,则可能会破坏事务的总体目标。原子性消
除了系统处理操作子集的可能性。
一致性(Consistency):事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。这种特性称
为事务的一致性。假如数据库的状态满足所有的完整性约束,说该数据库是一致的。
隔离性(Isolation):由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,
到底是另一个事务执行之前的状态还是中间某个状态,相互之间存在什么影响,是可以通过隔离级别的设置来控制的。
持久性(Durability):事务结束后,事务处理的结果必须能够得到固化,即写入数据库文件中即使机器宕机数据也不会丢
失,它对于系统的影响是性的。
事务并发控制
我们从另外一个方向来说说,如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形,有些使我们可
以接受的,有些是不能接受的,注意这里的异常是特定语境下的,并不一定是错误什么的。假设有一个order表,有个字段叫
count,作为计数用,当前值为100
第一类丢失更新(Update Lost):此种更新丢失是因为回滚的原因,所以也叫回滚丢失。此时两个事务同时更新count,
两个事务都读取到100,事务一更新成功并提交,count=100+1=101,事务二出于某种原因更新失败了,然后回滚,事务二把
count还原为它一开始读到的100,此时事务一的更新这样丢失了。
脏读(Dirty Read):此种异常时因为一个事务读取了另一个事务修改了但是未提交的数据。举个例子,事务一更新了
count=101,但是没有提交,事务二此时读取count,值为101而不是100,然后事务一出于某种原因回滚了,然后第二个事务
读取的这个值是噩梦的开始。
不可重复读(Not Repeatable Read):此种异常是一个事务对同一行数据执行了两次或更多次查询,但是却得到了不同
的结果,也是在一个事务里面你不能重复(即多次)读取一行数据,如果你这么做了,不能保证每次读取的结果是一样的,有
可能一样有可能不一样。造成这个结果是在两次查询之间有别的事务对该行数据做了更新操作。举个例子,事务一先查询了
count,值为100,此时事务二更新了count=101,事务一再次读取count,值会变成101,两次读取结果不一样。
第二类丢失更新(Second Update Lost):此种更新丢失是因为更新被其他事务给覆盖了,也可以叫覆盖丢失。举个例
子,两个事务同时更新count,都读取100这个初始值,事务一先更新成功并提交,count=100+1=101,事务二后更新成功并
提交,count=100+1=101,由于事务二count还是从100开始增加,事务一的更新这样丢失了。
幻读(Phantom Read):幻读和不可重复读有点像,只是针对的不是数据的值而是数据的数量。此种异常是一个事务在
两次查询的过程中数据的数量不同,让人以为发生幻觉,幻读大概是这么得来的吧。举个例子,事务一查询order表有多少条
记录,事务二新增了一条记录,然后事务一查了一下order表有多少记录,发现和第一次不一样,这是幻读。
数据库事务隔离级别
看到上面提到的几种问题,你可能会想,我擦,这么多坑怎么办啊。其实上面几种情况并不是一定都要避免的,具体看你
的业务要求,包括你数据库的负载都会影响你的决定。不知道大家发现没有,上面各种异常情况都是多个事务之间相互影响造
成的,这说明两个事务之间需要某种方式将他们从某种程度上分开,降低直至避免相互影响。这时候数据库事务隔离级别粉墨
登场了,而数据库的隔离级别实现一般是通过数据库锁实现的。
读未提交(Read Uncommitted):该隔离级别指即使一个事务的更新语句没有提交,但是别的事务可以读到这个改变,
几种异常情况都可能出现。极易出错,没有安全性可言,基本不会使用。
读已提交(Read Committed):该隔离级别指一个事务只能看到其他事务的已经提交的更新,看不到未提交的更新,消
除了脏读和第一类丢失更新,这是大多数数据库的默认隔离级别,如Oracle,Sqlserver。
可重复读(Repeatable Read):该隔离级别指一个事务中进行两次或多次同样的对于数据内容的查询,得到的结果是一
样的,但不保证对于数据条数的查询是一样的,只要存在读改行数据禁止写,消除了不可重复读和第二类更新丢失,这是
Mysql数据库的默认隔离级别。
串行化(Serializable):意思是说这个事务执行的时候不允许别的事务并发执行.完全串行化的读,只要存在读禁止写,
但可以同时读,消除了幻读。这是事务隔离的高级别,虽然安全省心,但是效率太低,一般不会用。
下面是各种隔离级别对各异常的控制能力: 级别异常 第一类更新丢失 脏读 不可重复读 第二类丢失更新 幻读 读未提交 Y
Y Y Y Y 读已提交 N N Y Y Y 可重复读 N N N N Y 串行化 N N N N N 数据库锁分类
一般可以分为两类,一个是悲观锁,一个是乐观锁,悲观锁一般是我们通常说的数据库锁机制,乐观锁一般是指用户自己
实现的一种锁机制,比如hibernate实现的乐观锁甚至编程语言也有乐观锁的思想的应用。
悲观锁:顾名思义,是很悲观,它对于数据被外界修改持保守态度,认为数据随时会修改,所以整个数据处理中需要将数
据加锁。悲观锁一般都是依靠关系数据库提供的锁机制,事实上关系数据库中的行锁,表锁不论是读写锁都是悲观锁。
悲观锁按照使用性质划分:
共享锁(Share locks简记为S锁):也称读锁,事务A对对象T加s锁,其他事务也只能对T加S,多个事务可以同时读,
评论0