?
- 事务的概念
事务(Transaction)是构成单一逻辑工作单元的数据库操作序列。这些操作是一个统一的整体,
要么全部成功执行(执行结果写到物理数据文件),要么全部不成功执行(执行结果没有写到任何的物理数据文件)。
- 事务的特性
原子性(Atomicity)
事务是数据库操作的逻辑工作单位。就操作而言,事务中的操作是一个整体,不能被分割,要么全部成功执行,要么全部不成功执行。
一致性(Consistency)
事务一致性是指事务执行前后都能够保持数据库状态的一致性,即事事务的执行结果是将数据库从一个一致状态转变为另一个一致状态。
隔离性(Isolation)
隔离性是指多个事务在执行时不相互干扰的一种特性。
持久性(Durability)
持久性,是指一个事务一旦成功提交,其结果对数据库的改变将是永久的,即使是出现系统故障问题。
事务的这四个特性通常被称为事务的ACID特性。这些特性可能在出现下列情况时遭到破坏:
- 当多个事务在并发执行时,存在不同事务的操作在交叉执行的情况;
- 事务在执行过程中被强行停止。
为保持事务的这种ACID特性,必须解决以上面临的问题,这也是并发控制要完成的任务。
- 启动事务
在SQL Server中,启动事务有:显示启动、自动提交和隐式启动
- 显示启动是以Begin Transaction命令开始的,当执行到该语句时,SQL Server将认为这是一个事务的起点。
- 自动提交。在自动提交方式下,每一条SQL语句就是一个事务,这是SQL Server的默认模式。
- 隐式启动。当Implicit_Transaction设置为on时,表示将隐式事务模式设置为打开。
- 终止事务
在SQL Server中,终止事务有:commit(提交命令),rollback(回滚命令)
- commit命令使得自从事务开始以来所执行的所有数据修改成为数据库的永久部分,释放事务所占用的资源。如果@@Trancount大于1,则commit 使@@Trancount按1递减并且事务将保持活动状态。
- rollback,它可以将显示事务或隐性事务回滚到事务起点或事务的某个保存点(savepoint)。
DEMO:
- 银行转账的问题:比如,将账号002上的2000元转到账号203上。为了使得不出现钱没到账(转出账号上已被扣钱,但转入账号上的余额并没有增加),
我们把转账操作涉及的关键语句放到一个事务中。
begin transaction virementdeclare @balance float,@x float;--设置转账金额set @x=2000;--如果转出账号上的金额小于x,则取消转账操作select @balance=balance from usertable where account='002';if(@balance<@x)return;--否则执行下列操作--从转出账号上扣除xupdate usertable set [email protected] where account='002';--在转入账号上加上xupdate usertable set [email protected] where account='203';--转账操作结束gocommit transaction virement;--提交事务,事务终止?
- 事务的全部回滚
use Test;gocreate table TestTransaction(c1 char(3),c2 char(3));gobegin transaction mytrans insert into TestTransaction values('aa1','aa2'); insert into TestTransaction values('bb1','bb2'); insert into TestTransaction values('cc1','cc2');rollback transaction mytrans insert into TestTransaction values('dd1','dd2'); insert into TestTransaction values('ee1','ee2');select * from TestTransaction
?结果为:
c1 | c2 | |
1 | dd1 | dd2 |
2 | ee1 | ee2 |
由于rollback语句对整个事务进行全部的回滚,使得数据库回到执行这三条插入语句之前的状态。
- 事务的部分回滚(有savepoint)
use Test;godrop table TestTransactioncreate table TestTransaction(c1 char(3),c2 char(3));gobegin transaction mytrans --开始事务 insert into TestTransaction values('aa1','aa2'); insert into TestTransaction values('bb1','bb2'); save transaction save1; --设置保存点 insert into TestTransaction values('cc1','cc2');rollback transaction save1; insert into TestTransaction values('dd1','dd2'); insert into TestTransaction values('ee1','ee2');select * from TestTransaction
?结果为:
c1 | c2 | |
1 | aa1 | aa2 |
2 | bb1 | bb2 |
3 | dd1 | dd2 |
4 | ee1 | ee2 |
- 并发控制
在单处理机系统中,事务的并发执行实际上是这些并行事务的并行操作轮流交叉运行,这种并发执行方式称为交叉并发方式。
虽然单处理机系统中的并行事务并没有真正地并行运行,但是减少了处理机的空闲时间,提高了系统的效率。
封锁
封锁是实现并发控制的一个重要技术。所谓封锁就是事务T在对某个数据对象操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象
有了一定的控制,在事务T释放它的锁之前,其他的事务不能更新此数据对象。
封锁的方法可能产生的2个问题:
活锁
如果事务T1封锁了数据R,事务T2又请求封锁R,于是T2等待。T3也请求封锁R,当T1释放R上的封锁之后系统首先批准了T3的请求,T2仍然等待。然后T4又请求封锁R,
当T3释放了R上的封锁之后系统又批准了T4的请求....T2有可能永远等待,这就是活锁的情形。
死锁
如果事务T1封锁了数据R1,T2封锁了数据R2,然后T1又请求封锁R2,因T2已封锁了R2,于是T1等待T2释放R2上的锁。接着T2又申请封锁R1,因T1已封锁了R1,T2
也只能等待T1释放R1上的锁。这样就出现了T1在等待T2,而T2又在等待T1的局面,T1和T2两个事务永远不能结束,形成死锁。
2段锁协议
所谓两段锁协议是指所有事务必须分两个阶段对数据项加锁和解锁。
- 在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁;
- 在释放一个封锁之后,事务不再申请和获得任何其他封锁;