SQL Server之事务基础知识
事务是对数据库执行的一个操作单位。
事务的本质特征:
所有的事务都有开始和结束;
事务可以被保存或撤销;
如果事务在中途失败,事务中的任何部分都不会被记录到数据库
控制事务
当一个事务被执行并成功完成时,虽然从输出结果来看目标表已经被修改了,但实际上目标表并不是立即被修改。
当事务成功完成时,利用事务控制命令最终认可这个事务,可以把事务所做的修改保存到数据库,也可以撤销事
务所做的修改。
commit命令
commit命令用于把事务所做的修改保存到数据库,它把上一个commit或rollback命令之后的全部事务都保存到
数据库。在执行 commit transaction语句后不能回滚事务。
rollback命令
rollback命令用于撤销还没有保存到数据库的命令,它只能用于撤销上一个commit或rollback命令之后的事务
savepoint命令(在sql中为save tran或save transaction)
保存点是事务过程中的一个逻辑点,我们可以把事务回退到这个点,而不必回退整个事务。
语法:savepoint savepoint_name
这个命令就是事务语句之间创建一个保存点。rollback命令可以撤销一组事务操作,而保存点可以将大量事务操作
划分为较小的、更易于管理的组。
insert into score values('F002','M006',99)
save tran sp1
insert into score values('F009','M007',100)
rollback tran sp1
commit //结果数据库中添加了第一条语句,而第二条语句还未保存到数据库
rollback to savepoint命令(Oracle数据库、DB2数据库 )
语法:rollback to savepoint_name
release savepoint命令(Oracle数据库、DB2数据库)
这个命令用于删除创建的保存点。在某个保存点被释放后,就不能在利用rollback命令来撤销这个保存点之后的事务
操作。利用这个命令可以避免意外地回退到某个不再需要的保存点。
语法:release savepoint savepoint_name
set transaction命令
这个命令用于初始化数据库事务,可以指定事务的特性。
我们知道在线程中常常会出现竞态或死锁的问题,其实在数据库中也会出现并发的问题。
那么如何解决数据库并发问题呢?
解决此问题的办法就是为数据库加锁,以防止多个组件读取数据,通过锁住事务所用的数据,能保证开锁之前,只有本事务才能
访问数据库。这样就避免了交叉存取的问题。
在sql server数据库中没有READ ONLY(只读锁)和READ WRITE(写入锁),但是在这里简单介绍一下。
只读锁是非独占的,多个并发的事务都能获得只读锁,只进行查询事务,很适合生成报告,而且能够提高事务完成的速度;
写入锁是独占的,任意时间只能有一个事务可以获得写入锁,可以对数据库进行查询和操作数据的事务。
如果事务是READ WRITE类型的,数据库必须对数据库对象进行加锁,从而在多个事务同时发生时保持数据完整性。
如果事务是READ ONLY类型的,数据库就不会建立锁定,这样就会提高事务的性能。
语法:
{READ ONLY}|{READ WRITE}|
{
ISOLATION LEVEL
【 READ COMMITTED
| READ UNCOMMITTED
| REPEATABLE READ
| SERIALIZABLE
】
}
四种事务的隔离级别
要理解这些隔离级别的差异,首先了解如下几个概念:脏读、不可重复读、幻影读取。
脏读:
假设同一个A和B两个同时并发操作数据库,A和B执行的任务如下:从数据库读取整数N,将N再加上10,将新的N更新回数据库。
这两个并发执行的实例可能发生下面的执行顺序。
1.A从数据库中读取整数N,当前数据库中N=0;
2.N加上10,并将其更新到数据库中,当前数据库中N=10,然而A的事务还没有提交,所以数据库更新还没有称之为持久性的。
3.B从数据库中读取整数N,当前数据库中N=0;
4.A回滚了事务,所以N恢复到了N=0;
5.B将N加上了10,并将其更新到数据库中,当前数据库中N=20。
这里出现了B在A提交前读取了A所更新的数据,由于A回滚了事务,所以数据库中出现了错误的数据20,尽管A回滚了事务,但是
A更新的数据还是间接的通过B被更新到了数据库中。这种读取了未提交的数据的方法就叫脏读问题。
不可重复读:
当一个用户从数据库中读取数据的时候,另外一个用户修改了这条数据,所以数据发送了改变,当再次读取的时候就出现了不可重
复读的问题。
幻影读取:
在两次数据库操作读取操作之间,一组新的数据会出现在数据库中,
1.A从数据库中检索到了一些数据;
2.B通过Insert插入一些新的数据;
3.A再次查询的时候,新的数据就会出现。
了解了这几个概念,下面来看一下四种事务的隔离级别的区别:
READ UNCOMMITTED
最低隔离级,允许脏读或 0 级隔离锁定,这表示不发出共享锁并忽略所以锁,也不接受排它锁。
READ COMMITTED
当数据正被读取时,可以控制共享锁。不允许脏读,但数据可在事务结束前更改,从而产生不可重复读取或幻像数据。该选项是 SQL Server 的默认值。
REPEATABLE READ
锁定查询中使用的所有数据以防止其他用户更新、删除数据等,但是其他用户可以将新的幻像行插入数据集,且可以读取。因为并发低于默认隔离级别,所以应只在必要时才使用该选项。
SERIALIZABLE
事务的最高隔离级,锁定整个数据集,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同。
事务的一个例子:
begin transaction
save tran sp1
insert into score values('F002','M006',99)
save tran sp2
insert into score values('F009','M007',100)
save tran sp3
delete from score where sid>=39
rollback tran sp2
commit