首先声明,以下是个人见解,如有错误望指出,先谢谢!
我们知道数据库(SQL) 的事务,现在我讲讲我的大概了解:
数据库的事务使用基本语法:
begin try begin tran [tranName] --语句 commit tran [tranName] end try begin catch rollback tran [tranName] end catch
[] 表示可有可无,
try catch 我就不说了。 数据库执行事务成功与否 看的是计数,即 begin tran 和 commit tran 的计数。当计数一样就成功,不成功报如下错误:
EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 1,当前计数 = 2 , 只要是两个计数不一样,就会出现错误
一般写事务就是一层,所以 有没有事务名一样,当事务有多层(存储过程调用存储过程,循环调用存储过程(存储过程都是带事务的)) 这时候事务名是很重要的
简单说一下,当有A(含事务) 存储过程调用B(含事务)存储过程,如果 B 事务不指定事务名,当B 回滚的时候会将 A 的存储过程 计数也回滚,导致两个计数不一致,
如果 B 事务指定事务名,将不会影响 A 事务的计数。这就是有事务名和没有事务名的区别,一句话:有事务名就是当前事务,没有事务名就是整个事务。
C# 中有个 SqlTransaction 类,怎么使用我就不说了,这个类的事务和数据库的事务是一样的,他们公用同一个进程,也就是说 在C# 类里有事务,在执行的SQL里
也有事务,当把SQL里的事务提交(没有指明事务名的情况) 会导致 C# 当前的 事务对象为null.
这里顺便说下: set xact_abort on 这个设置是指 出错后自动回滚,一般用在存储过程中。
下面给一个事务嵌套的例子:
表结构:
CREATE TABLE [dbo].[Test]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [nvarchar](5) NOT NULL ) ON [PRIMARY]
子事务:
CREATE procedure [dbo].[CreateSubTran] ( @Name nvarchar(50), @Status int output ) as begin begin try print ‘准备开始:‘+CAST(@@TRANCOUNT AS VARCHAR(50)) begin tran currentTran save tran preTran print ‘事务开始:‘+CAST(@@TRANCOUNT AS VARCHAR(50)) insert test(Name) values(@Name) set @Status=1 print ‘执行成功:‘+CAST(@@TRANCOUNT AS VARCHAR(50)) commit tran currentTran print ‘commit‘ end try begin catch print ‘出错回滚前:‘+CAST(@@TRANCOUNT AS VARCHAR(50)) if(@@TRANCOUNT>0) begin rollback tran preTran end set @Status=-1 commit tran currentTran print ‘出错回滚后:‘+CAST(@@TRANCOUNT AS VARCHAR(50)) return 0 end catch end
父事务:
create proc CreateParentTran as begin declare @result int begin try begin tran exec [CreateSubTran] ‘sdfsd‘,@result output commit tran end try begin catch rollback tran end catch end
注意: 最外层事务可以不用指定事务名,嵌套事务必须指定事务名,上面已经讲的很清楚。
如图结果:事务开始的计数必须与结束的计数是一样的
当事务执行回滚后,当前的计数 就等于事务还未开始前的计数。