日期:2014-05-16  浏览次数:20545 次

SQLServer数据库笔记(四)
数据库事务
SQLServer支持三类事务:自动提交事务、隐性事务和显式事务。其中,自动提交和隐性事务由“SET IMPLICIT_TRANSACTIONS {ON|OFF}”切换。
显式事务可以嵌套。按联机丛书的说明:
引用
这主要是为了支持存储过程中的一些事务,这些事务可以从事务中已有的进程中调用,也可以从没有活动事务的进程中调用。

嵌套事务本质上只有最外层事务起作用,内部事务的begin和commit被忽略了(可以看做是这样)。
SQLServer支持保存点,保存点用于回滚部分内部事务。
SQLServer支持SQL92的事务隔离级别(控制由连接发出的所有SELECT语句的默认事务锁定行为),分别是:
READ UNCOMMITTED
READ COMMITTED(缺省)
REPEATABLE READ
SERIALIZABLE

嵌套事务:“嵌套”只是一个形式,一个数据库连接上,最多同时只有一个事务存在。@@trancount变量用来决定内部事务的commit行为(究竟是该提交还是忽略)。
Begin transaction [name]只有最外层的语句才开启事务,事务内部的begin语句被忽略了。(仅仅使@trancount+1),也只有最外层的事务名称才有效(仅用于回滚时区分保存点名称),内部事务的名称仅仅是为代码更容易阅读。
Commit transaction [name]名称完全被忽略了。当@@trancount=1时提交事务,释放资源锁定。当事务不存在(@@trancount=0)时,将会引发一个错误。其他情况下,仅仅使@@trancount-1。
Rollback transaction [name]名称要么不写,如果写的话,必须是最外层事务名称或者保存点名称。其他任何名称都会引发一个错误。当事务不存在(@@trancount=0)时,引发一个错误。回滚保存点时,对事务计数(@@trancount)没有影响;否则回滚事务到事务起点,并令@@trancount=0(不管回滚前是多少)。
Save transaction <name>在事务内部设置一个保存点。名称是必须的。如果不在事务内部,将引发一个错误。
对存储过程的调用不应该导致@@trancount发生变化。联机丛书的描述:
引用
如果@@TRANCOUNT的值在存储过程完成时与过程执行时不同,则会生成一个266信息类错误。

再重述一下事务隔离级别控制由连接发出的所有SELECT语句的默认事务锁定行为的含义:
这句话的意思是说,insert/delete/update语句的锁定和自身的事务隔离级别没有关系,都是排他锁,并且直到事务结束才释放。
而select语句则按照事务隔离级别的不同,锁定方式不同。
READ UNCOMMITTED下,select不加锁,所以,可以读到其他事务未提交的数据,也就是允许脏读。
READ COMMITTED下,select语句加共享锁,如果其他事务在更新数据,同时尚未提交(排他锁还未释放),select语句就必须等待,所以,不会出现脏读。select语句执行完以后,共享锁就会释放(在事务提交前);但是和再次读取之间,其他事务可能会更改数据,也就是说存在不可重复读。
REPEATABLE READ下,共享锁的范围是本次读取影响的数据行或页。并且直到事务结束才释放锁,所以可以避免不可重复读。但是无法避免其他事务新增的记录也符合本次查询条件,所以会出现幻像读。
SERIALIZABLE下,采用的是键范围锁模式,直到事务结束才释放锁。这样可以避免幻像读。
下面摘自联机丛书:
引用
  • 共享锁:共享 (S) 锁允许并发事务读取 (SELECT) 一个资源。资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。一旦已经读取数据,便立即释放资源上的共享 (S) 锁,除非将事务隔离级别设置为可重复读或更高级别,或者在事务生存周期内用锁定提示保留共享 (S) 锁。
  • 排它锁:用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。排它 (X) 锁可以防止并发事务对资源进行访问。其它事务不能读取或修改排它 (X) 锁锁定的数据。
  • 键范围锁定:键范围锁定解决了幻像读并发问题,并支持可串行事务。键范围锁覆盖单个记录以及记录之间的范围,可以防止对事务访问的记录集进行幻像插入或删除。键范围锁仅用于代表在可串行隔离级别上操作的事务。
  • 锁升级:锁升级是将众多细粒度锁转换为较少的粗粒度的锁的过程,以削减系统开销。当事务超过它的升级极限时, SQL Server自动将行锁和页锁升级为表锁。