事务全攻略[转]

 

关于事务

一  事务的属性  
 
事务具有ACID属性 : 
即  Atomic原子性,  Consistent一致性,  Isolated隔离性,  Durable永久性  
 
1,原子性:  就是事务应作为一个工作单元,事务处理完成,所有的工作要么都在数据库中保存下来,要么完全  
回滚,全部不保留  
 
 
2,一致性 :事务完成或者撤销后,都应该处于一致的状态  
 
3,隔离性: 
     多个事务同时进行,它们之间应该互不干扰.应该防止一个事务处理其他事务也要修改的数据时,  
不合理的存取和不完整的读取数据  
 
 
4,永久性 : 
     事务提交以后,所做的工作就被永久的保存下来  
 
 
二  事务并发处理会产生的问题    
 
1,丢失更新  
     当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题、  
每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。  
 
2,脏读  
     当第二个事务选择其它事务正在更新的行时,会发生未确认的相关性问题。  
     第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。  
 
3,不可重复读  
      当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。  
      不一致的分析与未确认的相关性类似,因为其它事务也是正在更改第二个事务正在读取的数据。  
      然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。  
 
4,幻像读  
      当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。  
      事务第一次读的行范围显示出其中一行已不复存在于第二次读或后续读中,因为该行已被其它事务删除。同样,由于其它事务的插入操作,事务的第二次或后续读显示有一行已不存在于原始读中。  
 
 
三  事务处理类型  
 
 
1,自动处理事务  
      系统默认每个T-SQL命令都是事务处理    由系统自动开始并提交  
 
 
2,隐式事务  
      当有大量的DDL  和DML命令执行时会自动开始,并一直保持到用户明确提交为止,切换隐式事务可以用SET  IMPLICIT_TRANSACTIONS  
      为连接设置隐性事务模式.当设置为  
ON  时,SET  IMPLICIT_TRANSACTIONS  将连接设置为隐性事务模式。当设置为  OFF  时,则使连接返回到自动提交事务模式  
 
 
3,用户定义事务  
      由用户来控制事务的开始和结束    命令有:  
begin  tran  commit  tran    rollback  tran  命令  
 
 
4,分布式事务  
      跨越多个服务器的事务称为分布式事务,sql  server  可以由DTc  microsoft  
distributed  transaction  coordinator  
      来支持处理分布式事务,可以使用  
BEgin  distributed  transaction  命令启动一个分布式事务处理  
 
 
 
四    事务处理的隔离级别  
      使用SET  
TRANSACTION  ISOLATION  LEVEL来控制由连接发出的所有语句的默认事务锁定行为从低到高
依次是 
READ  UNCOMMITTED  
 
执行脏读或 
0 级隔离锁定,这表示不发出共享锁,也不接受排它锁。当设置该选项时,可以对数据执行未提交读或脏读;在事务结束前可以更改数据内的数值,行也可以出现在数据集中或从数据集消失。该选项的作用与在事务内所有语句中的所有表上设置  NOLOCK  相同。这是四个隔离级别中限制最小的级别。  
 
举例  
 
设table1(A,B,C)  
A        B        C  
a1      b1      c1  
a2      b2      c2  
a3      b3      c3  
 
新建两个连接  
在第一个连接中执行以下语句  
select  *  from  table1  
begin  tran  
update  table1  set  c='c'  
select  *  from  table1  
waitfor  delay  '00:00:10'    --等待10秒  
rollback  tran  
select  *  from  table1  
 
在第二个连接中执行以下语句  
SET  TRANSACTION  ISOLATION  LEVEL  READ  UNCOMMITTED  
print  '脏读'  
select  *  from  table1  
if  @@rowcount>0  
begin  
 
waitfor  delay  '00:00:10'    
 
print  '不重复读'  
 
select  *  from  table1  
end  
 
第二个连接的结果  
 
脏读  
A        B        C  
a1      b1      c  
a2      b2      c  
a3      b3      c  
 
'不重复读'  
A        B        C  
a1      b1      c1  
a2      b2      c2  
a3      b3      c3  
 
 
 
READ  COMMITTED  
 
指定在读取数据时控制共享锁以避免脏读,但数据可在事务结束前更改,从而产生不可重复读取或幻像数据。该选项是  SQL  Server  的默认值。  
 
 
在第一个连接中执行以下语句  
SET  TRANSACTION  ISOLATION  LEVEL  READ  COMMITTED  
begin  tran  
print  '初始'  
select  *  from  table1  
waitfor  delay  '00:00:10'    --等待10秒  
print  '不重复读'  
select  *  from  table1  
rollback  tran  
 
 
在第二个连接中执行以下语句  
SET  TRANSACTION  ISOLATION  LEVEL  READ  COMMITTED  
 
update  table1  set  c='c'  
     
 
第一个连接的结果  
 
初始  
A        B        C  
a1      b1      c1  
a2      b2      c2  
a3      b3      c3  
 
不重复读  
A        B        C  
a1      b1      c  
a2      b2      c  
a3      b3      c  
 
 
 
REPEATABLE  READ  
 
锁定查询中使用的所有数据以防止其他用户更新数据,但是其他用户可以将新的幻像行插入数据集,且幻像行包括在当前事务的后续读取中。因为并发低于默认隔离级别,所以应只在必要时才使用该选项。  
 
 
在第一个连接中执行以下语句  
SET  TRANSACTION  ISOLATION  LEVEL  REPEATABLE  READ  
begin  tran  
print  '初始'  
select  *  from  table1  
waitfor  delay  '00:00:10'    --等待10秒  
print  '幻像读'  
select  *  from  table1  
rollback  tran  
 
 
在第二个连接中执行以下语句  
SET  TRANSACTION  ISOLATION  LEVEL  REPEATABLE  READ  
insert    table1  select  'a4','b4','c4'  
 
 
第一个连接的结果  
 
初始  
A        B        C  
a1      b1      c1  
a2      b2      c2  
a3      b3      c3  
 
幻像读  
A        B        C  
a1      b1      c1  
a2      b2      c2  
a3      b3      c3  
a4      b4      c4  
 
 
SERIALIZABLE  
 
在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。这是四个隔离级别中限制最大的级别。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有  
SELECT  语句中的所有表上设置  HOLDLOCK  相同。  
 
 
在第一个连接中执行以下语句  
SET  TRANSACTION  ISOLATION  LEVEL  SERIALIZABLE  
begin  tran  
print  '初始'  
select  *  from  table1  
waitfor  delay  '00:00:10'    --等待10秒  
print  '没有变化'  
select  *  from  table1  
rollback  tran  
 
 
在第二个连接中执行以下语句  
SET  TRANSACTION  ISOLATION  LEVEL  SERIALIZABLE  
insert    table1  select  'a4','b4','c4'  
 
 
第一个连接的结果  
 
初始  
A        B        C  
a1      b1      c1  
a2      b2      c2  
a3      b3      c3  
 
没有变化  
A        B        C  
a1      b1      c1  
a2      b2      c2  
a3      b3      c3  
 
 
五  事务处理嵌套的语法和对
@@TRANCOUNT的影响  
 
BEGIN  TRAN    @@TRANCOUNT1  
COMMIT  TRAN  @@TRANCOUNT1  
ROLLBACK  TR  

 

 

 

sp_lock2
Version: SQL Server 
7.0/2000
Created 
by: Alexander Chigrik
http:
//www.MSSQLCity.com/ - all about MS SQL
(SQL Server Articles, FAQ, Scripts, Tips 
and Test Exams). 

This stored 
procedure can be used instead of sp_lock system stored procedure
to return more detailed locking view (it can return user name, host name,
database name, object name, index name and object owner).
This 
is the example to use sp_lock2:

EXEC sp_lock2

/*
Version: SQL Server 7.0/2000
Created by: Alexander Chigrik
http://www.MSSQLCity.com/ - all about MS SQL
(SQL Server Articles, FAQ, Scripts, Tips and Test Exams).

This stored procedure can be used instead of sp_lock stored procedure
to return more detailed locking view (it can return user name, host name,
database name, object name, index name and object owner).
This is the example to use sp_lock2:

EXEC sp_lock2
*/


USE MASTER
GO
IF OBJECT_ID('sp_lock2'IS NOT NULL DROP PROC sp_lock2
GO
CREATE PROCEDURE sp_lock2
@spid1 int = NULL,      /* server process id to check for locks */
@spid2 int = NULL       /* other process id to check for locks */
as

set nocount on
/*
** Show the locks for both parameters.
*/

declare @objid int,
   
@indid int,
   
@dbid int,
   
@string Nvarchar(255)

CREATE TABLE #locktable
   (
   spid       
smallint
   ,loginname 
nvarchar(20)
   ,hostname  
nvarchar(30)
   ,dbid      
int
   ,dbname    
nvarchar(20)
   ,ObjOwner  
nvarchar(128)
   ,objId     
int
   ,ObjName   
nvarchar(128)
   ,IndId     
int
   ,IndName   
nvarchar(128)
   ,Type      
nvarchar(4)
   ,Resource  
nvarchar(16)
   ,Mode      
nvarchar(8)
   ,Status    
nvarchar(5)
   )

if @spid1 is not NULL
begin
   
INSERT #locktable
      (
      spid
      ,loginname
      ,hostname
      ,dbid
      ,dbname
      ,ObjOwner
      ,objId
      ,ObjName
      ,IndId
      ,IndName
      ,Type
      ,Resource
      ,Mode
      ,Status
      )
   
select convert (smallint, l.req_spid)
      ,
coalesce(substring (s.loginame, 120),'')
      ,
coalesce(substring (s.hostname, 130),'')
      ,l.rsc_dbid
      ,
substring (db_name(l.rsc_dbid), 120)
      ,
''
      ,l.rsc_objid
      ,
''
      ,l.rsc_indid
      ,
''
      ,
substring (v.name, 14)
      ,
substring (l.rsc_text, 116)
      ,
substring (u.name, 18)
      ,
substring (x.name, 15)
   
from master.dbo.syslockinfo l,
      master.dbo.spt_values v,
      master.dbo.spt_values x,
      master.dbo.spt_values u,
      master.dbo.sysprocesses s
   
where l.rsc_type = v.number
   
and   v.type = 'LR'
   
and   l.req_status = x.number
   
and   x.type = 'LS'
   
and   l.req_mode + 1 = u.number
   
and   u.type = 'L'
   
and   req_spid in (@spid1@spid2)
   
and   req_spid = s.spid
end
/*
** No parameters, so show all the locks.
*/

else
begin
   
INSERT #locktable
      (
      spid
      ,loginname
      ,hostname
      ,dbid
      ,dbname
      ,ObjOwner
      ,objId
      ,ObjName
      ,IndId
      ,IndName
      ,Type
      ,Resource
      ,Mode
      ,Status
      )
   
select convert (smallint, l.req_spid)
      ,
coalesce(substring (s.loginame, 120),'')
      ,
coalesce(substring (s.hostname, 130),'')
      ,l.rsc_dbid
      ,
substring (db_name(l.rsc_dbid), 120)
      ,
''
      ,l.rsc_objid
      ,
''
      ,l.rsc_indid
      ,
''
      ,
substring (v.name, 14)
      ,
substring (l.rsc_text, 116)
      ,
substring (u.name, 18)
      ,
substring (x.name, 15)
   
from master.dbo.syslockinfo l,
      master.dbo.spt_values v,
      master.dbo.spt_values x,
      master.dbo.spt_values u,
      master.dbo.sysprocesses s
   
where l.rsc_type = v.number
   
and   v.type = 'LR'
   
and   l.req_status = x.number
   
and   x.type = 'LS'
   
and   l.req_mode + 1 = u.number
   
and   u.type = 'L'
   
and   req_spid = s.spid
   
order by spID
END
DECLARE lock_cursor CURSOR
FOR SELECT dbid, ObjId, IndId FROM #locktable
  
WHERE Type <>'DB' and Type <> 'FIL'

OPEN lock_cursor
FETCH NEXT FROM lock_cursor INTO @dbid@ObjId@IndId
WHILE @@FETCH_STATUS = 0
   
BEGIN

   
SELECT @string =
      
'USE ' + db_name(@dbid+ char(13)
      
+ 'update #locktable set ObjName = name, ObjOwner = USER_NAME(uid)'
      
+ ' from sysobjects where id = ' + convert(varchar(32),@objid)
      
+ ' and ObjId = ' + convert(varchar(32),@objid)
      
+ ' and dbid = ' + convert(varchar(32),@dbId)

   
EXECUTE (@string)

   
SELECT @string =
      
'USE ' + db_name(@dbid+ char(13)
      
+ 'update #locktable set IndName = i.name from sysindexes i '
      
+ ' where i.id = ' + convert(varchar(32),@objid)
      
+ ' and i.indid = ' + convert(varchar(32),@indid)
      
+ ' and ObjId = ' + convert(varchar(32),@objid)
      
+ ' and dbid = ' + convert(varchar(32),@dbId)
      
+ ' and #locktable.indid = ' + convert(varchar(32),@indid)

   
EXECUTE (@string)

   
FETCH NEXT FROM lock_cursor INTO @dbid@ObjId@IndId
   
END
CLOSE lock_cursor
DEALLOCATE lock_cursor

SELECT * FROM #locktable
return (0)
-- END sp_lock2
GO
posted @ 2007-03-15 16:02  吴东雷  阅读(445)  评论(0编辑  收藏  举报