0

当我执行以下代码(案例 1)时,我得到计数​​的值 2。这意味着在同一个事务中,对表所做的 chagnes 是可见的。所以这符合我的预期。

情况1

begin tran mytran
begin try

CREATE TABLE [dbo].[ft](
    [ft_ID] [int] IDENTITY(1,1) NOT NULL,
    [ft_Name] [nvarchar](100) NOT NULL
 CONSTRAINT [PK_FileType] PRIMARY KEY CLUSTERED 
(
    [ft_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]

INSERT INTO [dbo].[ft]([ft_Name])
VALUES('xxxx')
INSERT INTO [dbo].[ft]([ft_Name])
VALUES('yyyy')

select count(*) from [dbo].[ft]

commit tran mytran
end try
begin catch
rollback tran mytran
end catch

但是,当我更改一列(例如,在事务中添加新列)时,(自身/相同)事务(案例 2 )不可见。假设有一个产品表没有名为 ft_ID 的列,我正在添加一个具有相同事务的列并读取它。

案例2

begin tran mytran
begin try

IF NOT EXISTS (
  SELECT * 
  FROM   sys.columns 
  WHERE  object_id = OBJECT_ID(N'dbo.Products') 
         AND name = 'ft_ID'
)
begin
alter table dbo.Products 
add ft_ID int null
end

select ft_ID from dbo.Products


commit tran mytran
end try
begin catch
rollback tran mytran
end catch

当尝试执行案例 2时,我收到错误“无效的列名 'ft_ID'”,因为新添加的列在同一事务中不可见。

为什么会出现这种差异?Create table 是原子的(案例 1)并且以我期望的方式工作,但 alter table 不是。为什么在同一事务中所做的更改对向下的语句不可见(案例 2)。

4

2 回答 2

2

你得到一个编译错误。批处理永远不会启动执行。请参阅了解 SQL Server 如何执行查询。事务可见性和边界与您所看到的无关。

您应该始终将 DDL 和 DML 分成单独的请求。无需赘述,由于恢复的工作方式,在同一个事务中混合 DDL 和 DML 只是自找麻烦。相信我的话。

于 2013-10-31T07:58:37.210 回答
1

使用批次的规则
...
不能更改表,然后在同一批次中引用新列。

看到这个

另一种方法是生成一个子批次并从那里引用您的新列,例如...

exec('select ft_ID from dbo.Products')

然而,正如 Remus 所说,在混合模式更改和从该模式中选择数据时要非常小心,尤其是在同一个事务中。即使没有事务,此代码也会有副作用:尝试将此 exec() 解决方法包装在存储过程中,每次调用它时都会重新编译。运气不好,但它就是这样工作的。

于 2013-10-31T07:58:47.697 回答