触发器回滚举例: 我们看到许多注册系统在注册后都不能更改用户名,但这多半是由应用程序决定的, 如果直接打开数据库表进行更改,同样可以更改其用户名,在触发器中利用回滚就可以巧妙地实现无法更改用户名。 use 数据库名 go create trigger tr on 表名 for update as if update(userName) rollback tran关键在最后两句,其解释为:如果更新了 userName 列,就回滚事务。
begin try begin tran .... commit end try begin catch rollback raiserror('错误信息',16,1) end catch以上内容放在触发器中。
A.当 SET XACT_ABORT 为 ON 时,如果执行 Transact-SQL 语句产生运行时错误,则整个事务将终止并回滚。 B.当 SET XACT_ABORT 为 OFF 时,有时只回滚产生错误的 Transact-SQL 语句,而事务将继续进行处理。 如果错误很严重,那么即使 SET XACT_ABORT 为 OFF,也可能回滚整个事务。
看下这个CREATE TABLE [dbo].[NsCostRec]( [FStockID] [int] NOT NULL, [FItemID] [int] NOT NULL, [FDate] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL, [FAmount] [decimal](18, 6) NOT NULL, [FAmount1] [decimal](18, 6) NOT NULL, [FPreAmount] [decimal](18, 6) NOT NULL, CONSTRAINT [PK_NsCostRec] PRIMARY KEY CLUSTERED ( [FStockID] ASC, [FItemID] ASC, [FDate] ASC )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] -- FStockID,FItemID,FDate为主键 --执行下面一个事务 begin tran update AXiStockInto set FTheFirstTimeID=2,FTheFirstTimeDate='2009-04-10',FTheFirstTimeTime='08:57:22' where finterid=93 if @@Error=0 begin end else begin rollback tran end insert into NsCostRec(FStockID, FItemID, FDate, FAmount, FAmount1, FPreAmount) values(1773, 1815, '2009-04-09', 1200.000015, 1200.000000, 0.000000) if @@Error=0 begin end else begin rollback tran end insert into NsCostRec(FStockID, FItemID, FDate, FAmount, FAmount1, FPreAmount) values(1773, 1815, '2009-04-09', 1200.000015, 1200.000000, 0.000000) if @@Error=0 begin end else begin rollback tran end commit tran
1.set xact_abort off 2.设置保存点 IF OBJECT_ID('TA')IS NOT NULL DROP TABLE TA GO CREATE TABLE TA( ID INT IDENTITY,性別 NVARCHAR(5) CHECK(性別 IN(N'男',N'女'))) IF OBJECT_ID('PRO_TEST')IS NOT NULL DROP PROC PRO_TEST GO CREATE PROC PRO_TEST @SEX NVARCHAR(5) AS INSERT TA SELECT @SEX GO IF OBJECT_ID('TB')IS NOT NULL DROP TABLE TB GO CREATE TABLE TB(ID INT ,[NAME] VARCHAR(10)) INSERT TB SELECT 1,'張三' IF OBJECT_ID('TRI_TEST')IS NOT NULL DROP TRIGGER TRI_TEST GO CREATE TRIGGER TRI_TEST ON TB FOR UPDATE AS set xact_abort off IF UPDATE(ID) save tran procTran EXEC PRO_TEST 'TEST' IF(@@error <> 0) ROLLBACK TRAN procTran ELSE COMMIT TRAN procTranset xact_abort on GOUPDATE TB SET ID=888 WHERE ID=1 select * from tb /* ID NAME ----------- ---------- 888 張三(1 行受影响) */
我们看到许多注册系统在注册后都不能更改用户名,但这多半是由应用程序决定的, 如果直接打开数据库表进行更改,同样可以更改其用户名,在触发器中利用回滚就可以巧妙地实现无法更改用户名。
use 数据库名
go
create trigger tr
on 表名
for update
as
if update(userName)
rollback tran关键在最后两句,其解释为:如果更新了 userName 列,就回滚事务。
begin tran
....
commit
end try
begin catch
rollback
raiserror('错误信息',16,1)
end catch以上内容放在触发器中。
写事务,出错只回滚当前事务,不回滚原操作,如
UPDATE操作
触发器触发
执行触发器里的代码,这里出错只回滚这里,不要影响原UPDATE操作
这样会回滚原操作,如UPDATE,INSERT等 操作都会被回滚
估计是你没有判断@@error是否等于0?等于0是没有错误,不等于0都是错误大概的格式:
create trigger trg_test
......begin tranupdate ......
if @@error<>0 goto errcommit tran
returnerr:
rollback tran
if 'a'='a'commit
else
rollback
B.当 SET XACT_ABORT 为 OFF 时,有时只回滚产生错误的 Transact-SQL 语句,而事务将继续进行处理。
如果错误很严重,那么即使 SET XACT_ABORT 为 OFF,也可能回滚整个事务。
[FStockID] [int] NOT NULL,
[FItemID] [int] NOT NULL,
[FDate] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
[FAmount] [decimal](18, 6) NOT NULL,
[FAmount1] [decimal](18, 6) NOT NULL,
[FPreAmount] [decimal](18, 6) NOT NULL,
CONSTRAINT [PK_NsCostRec] PRIMARY KEY CLUSTERED
(
[FStockID] ASC,
[FItemID] ASC,
[FDate] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
--
FStockID,FItemID,FDate为主键
--执行下面一个事务
begin tran
update AXiStockInto set FTheFirstTimeID=2,FTheFirstTimeDate='2009-04-10',FTheFirstTimeTime='08:57:22' where finterid=93
if @@Error=0
begin
end
else
begin
rollback tran
end insert into NsCostRec(FStockID, FItemID, FDate, FAmount, FAmount1, FPreAmount) values(1773, 1815, '2009-04-09', 1200.000015, 1200.000000, 0.000000)
if @@Error=0
begin
end
else
begin
rollback tran
end insert into NsCostRec(FStockID, FItemID, FDate, FAmount, FAmount1, FPreAmount) values(1773, 1815, '2009-04-09', 1200.000015, 1200.000000, 0.000000)
if @@Error=0
begin
end
else
begin
rollback tran
end
commit tran
2.设置保存点
IF OBJECT_ID('TA')IS NOT NULL DROP TABLE TA
GO
CREATE TABLE TA( ID INT IDENTITY,性別 NVARCHAR(5) CHECK(性別 IN(N'男',N'女')))
IF OBJECT_ID('PRO_TEST')IS NOT NULL DROP PROC PRO_TEST
GO
CREATE PROC PRO_TEST
@SEX NVARCHAR(5)
AS
INSERT TA SELECT @SEX
GO
IF OBJECT_ID('TB')IS NOT NULL DROP TABLE TB
GO
CREATE TABLE TB(ID INT ,[NAME] VARCHAR(10))
INSERT TB SELECT 1,'張三'
IF OBJECT_ID('TRI_TEST')IS NOT NULL DROP TRIGGER TRI_TEST
GO
CREATE TRIGGER TRI_TEST ON TB
FOR UPDATE
AS
set xact_abort off
IF UPDATE(ID)
save tran procTran
EXEC PRO_TEST 'TEST'
IF(@@error <> 0)
ROLLBACK TRAN procTran
ELSE
COMMIT TRAN procTranset xact_abort on
GOUPDATE TB SET ID=888 WHERE ID=1
select * from tb
/*
ID NAME
----------- ----------
888 張三(1 行受影响)
*/