SQL Server中事务transaction如果没写在try catch中,就算中间语句报错还是会提交

假如我们数据库中有两张表Person和Book

Person表:

CREATE TABLE [dbo].[Person](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Code] [nvarchar](50) NULL,
    [Name] [nvarchar](50) NULL,
    [CreateTime] [datetime] NULL,
    [UpdateTime] [datetime] NULL,
 CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Person] ADD  CONSTRAINT [DF_Person_CreateTime]  DEFAULT (getdate()) FOR [CreateTime]
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_Person] ON [dbo].[Person]
(
    [Code] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

Book表:

CREATE TABLE [dbo].[Book](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [BookCode] [nvarchar](50) NULL,
    [BookName] [nvarchar](50) NULL,
    [PersonCode] [nvarchar](50) NULL,
 CONSTRAINT [PK_Book] PRIMARY KEY CLUSTERED
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Book]  WITH CHECK ADD  CONSTRAINT [FK_Book_Person] FOREIGN KEY([PersonCode])
REFERENCES [dbo].[Person] ([Code])
ON UPDATE CASCADE
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[Book] CHECK CONSTRAINT [FK_Book_Person]
GO

可以看到Person表和Book表是一对多关系,一个Person可以有多个Book,所以Book表的PersonCode列是外键,指向Person表的Code列,并为强制约束,也就是说Book表的PersonCode列的值,只能是Person表的Code列值,否则SQL Server会报错:

现在我们执行下面语句给两张表插入数据,我们将插入Person表和Book表的两个Insert语句写在了个事务transaction中,按道理其中一个Insert执行失败,另一个就不会执行:

BEGIN TRAN

INSERT INTO Person([Code],[Name])
VALUES(‘P003‘,‘Jack‘)

INSERT INTO [dbo].[Book]([BookCode],[BookName],[PersonCode])
VALUES
(‘B001‘,‘B001‘,‘P003‘),
(‘B002‘,‘B002‘,‘P003‘),
(‘B003‘,‘B003‘,‘P003‘),
(‘B004‘,‘B004‘,‘P003‘),
(‘B005‘,‘B005‘,‘XXX‘)--由于Book表的[PersonCode]列值‘XXX‘在Person表的[Code]列中不存在,所以整个INSERT INTO [dbo].[Book]语句会报错不会执行

COMMIT

由于值"XXX"在Person表的[Name]列中不存在,所以INSERT INTO [dbo].[Book]语句报错没有执行,但是我们意外地发现INSERT INTO Person却随着事务Commit一起提交了。。。Person表的数据被成功插入了。。。

(1 行受影响)
消息 547,级别 16,状态 0,第 7 行
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Book_Person". The conflict occurred in database "TestDB", table "dbo.Person", column ‘Code‘.
The statement has been terminated.

查询Person表数据:

查询Book表数据:

这是因为INSERT INTO [dbo].[Book]语句虽然报错没执行,但是最下面的Commit语句却执行了,也就是说INSERT INTO [dbo].[Book]语句报错,并没有阻止后面Commit语句的执行,所以INSERT INTO Person语句随着事务被提交到数据库生效了。。。

现在我们更改上面的语句如下,将两个Insert语句都放到try catch中:

BEGIN TRAN

BEGIN TRY

    INSERT INTO Person([Code],[Name])
    VALUES(‘P003‘,‘Jack‘)

    INSERT INTO [dbo].[Book]([BookCode],[BookName],[PersonCode])
    VALUES
    (‘B001‘,‘B001‘,‘P003‘),
    (‘B002‘,‘B002‘,‘P003‘),
    (‘B003‘,‘B003‘,‘P003‘),
    (‘B004‘,‘B004‘,‘P003‘),
    (‘B005‘,‘B005‘,‘XXX‘)--由于Book表的[PersonCode]列值‘XXX‘在Person表的[Code]列中不存在,所以整个INSERT INTO [dbo].[Book]语句会报错不会执行

    COMMIT

END TRY
BEGIN CATCH

    ROLLBACK 

END CATCH

运行后,我们再查询Person表的数据:

查询Book表数据:

我们可以看到这次就和我们的预期一致了,在INSERT INTO [dbo].[Book]语句报错后,后面的Commit语句没有执行,执行了catch中的Rollback,最后两张表的数据都没有插入数据库。

原文地址:https://www.cnblogs.com/OpenCoder/p/9800638.html

时间: 2024-08-27 00:06:34

SQL Server中事务transaction如果没写在try catch中,就算中间语句报错还是会提交的相关文章

(转)SQL Server 的事务和锁(一)

SQL Server 的事务和锁(一) 最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 SELECT @findCount=COUNT(id) FROM MyTable WHERE [fk_related_id][email protected] IF (@findCount > 0) BEGIN     ROLLBACK TRANSACTION     RET

SQL SERVER之事务

 在实际对数据库的使用中,会出现多个用户同时对某一张表进行操作,当多个用户在同一时间对同一张数据表进行读取或者修改操作时,若处理不当就有可能发生冲突问题.为了解决这样的问题,就需要使用事务的控制和管理机制. 事务 单个逻辑工作单元执行操作的集合,也可以看作是多条语句封装的结果.通过事务可以保证数据表中数据的一致性. 事务的特性 原子性 是指事务中所有的执行操作,要么全部成功,要么不执行.如在商场购物中,管理员同时对用户进行充值操作. 修改账户A中的现金数. 修改账户A中的现金数 如果在执行第

XenDesktop 5 SQL Server Mirror事务日志比较大的原因分析

在实施XenDesktop5项目过程中,发现XenDesktop5版本的数据库镜像事务日志很大,在XenDesktop4和XenApp版本中不存在该问题:于是我根据该现象探究XenDesktop5及以上版本镜像数据库事务日志为何如此之大以及我们今后实施的过程中该如何来维护这么庞大的数据库事务日志. 在XenDesktop解决方案中,对数据的处理是由专门的数据库来进行数据存储处理的,而对于数据库的高可用,有3种方式: SQL Mirror Virtual Machine HA(VMware FT)

如何读懂SQL Server的事务日志

简介 本文将介绍SQL Server的事务日志中记录了哪一些信息,如何来读懂这些事务日志中信息.首先介绍一个微软没有公开的函数fn_dblog,在文章的接下来的部分主要用到这个函数来读取事务日志. fn_dblog(@StartingLSN,@EndingLSN) [email protected]:表示起始的LSN号,如果为NULL值则表示从首日志记录开始查询. [email protected]:表示结束的LSN号,如果为NULL值则表示查询到尾日志记录. --需要注意的是我们平时所看到的L

SQL Server 分布式事务与本地事务

SQL Server 分布式事务与本地事务 @(SQL Server) 背景:之前有项目中出现大量死锁,进行排查后最终发现很多死锁都是由于序列化隔离级别导致,开发针对业务和SQL进行优化后,死锁减少,但是没进行后续研究.最近又有很多项目出现死锁及超时,特别是工作流和待办这块,同样发现都是存在序列化,于是针对这一点进行相关资料查阅及解答. 一. 为什么会出现serializable(序列化) 如果我们程序中定义事务类调用了分布式事务,那么事务的隔离级别默认就是serializable,数据库中即会

SQL Server Log文件对磁盘的写操作大小是多少

原文:SQL Server Log文件对磁盘的写操作大小是多少 SQL Server 数据库有三种文件类型,分别是数据文件.次要数据文件和日志文件,其中日志文件包含着用于恢复数据库的所有日志信息,SQL Server总是先写日志文件ldf,数据变化写入mdf则可以滞后,所以日志写入的速度在一定程序上决定了SQL Server所能承载的写事务量,那么ldf写入大小是多少呢? 要知道SQL Server写 Log的大小,这里使用工具Process Monitor 这里设置一个Filter,以满足只收

XenDesktop SQL Server Mirror事务日志维护

当使用SQL Server高可用性功能的时候,例如,XenDesktop站点数据库使用完整的事务日志记录模式下运行的数据库镜像. 通过完整的事务日志记录模式下运行的事务日志会增长过大,直到数据库空间被填满或事务日志空间大小被填满.如果事务日志文件不会被监视的,默认情况下,SQL Server的配置日志文件会自动增长.这将导致2个问题: 1.事务日志文件会占用大量的磁盘空间 2.事物日志增长填满数据库空间,导致数据库不可用. 因此Citrix建议定期备份日志文件.这可以通过调度作业或维护计划来完成

SQL Server数据库事务日志序列号(LSN)介绍

原文:http://blog.csdn.net/tjvictor/article/details/5251463 ? ? 日志序列编号(LSN)是事务日志里面每条记录的编号. 当你执行一次备份时,一些LSN值就被同时存储在文件本身及msdb..backupset表中.你可以使用RESTORE HEADERONLY语法来从备份文件中获取LSN值. ? 注意:在SQL Server 2000中,有一列叫做DifferentialBaseLSN.但在SQL Server 2005中,相同的列名称变成了

SQL Server备份事务日志结尾(Tail)

原文:http://blog.csdn.net/tjvictor/article/details/5256906 ? 事务日志结尾经常提交数据库未备份的事务日志内容.基本上,每一次你执行事务日志备份时,你都在执行事务日志结尾的备份. 那为什么会这么设计呢?因为也许由于介质的损坏,当数据库已经不再可用时,麻烦就来了.如果下一个逻辑步骤正好就是要备份当前事务日志的话,可以应用这个备份来使数据库处于等待(Standby)状态.你甚至可以在数据库文件不可用的状态下使用NO_TRUNCATE来备份事务日志