2013-10-31 31 views
0

当我执行下面的代码(案例1)我得到值为2的计数。这意味着在同一个交易中,桌子上的chagnes是可见的。所以这个行为就像我期望的那样。SQL服务器事务可见性问题

案例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'”,因为新添加的列是不可见在同一事务中。

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

回答

2

你得到一个编译错误。该批从未启动执行。请参阅Understanding how SQL Server executes a query。交易可见性和边界与您所看到的无关。

您应该始终将DDL和DML分隔成不同的请求。由于恢复工作的方式,在不涉及太多细节的情况下,在同一事务中混合使用DDL和DML只是要求麻烦。请在这一点上说说我的话。

+0

你能解释为什么案例1工作,但为什么案例2失败。为什么Micosoft以这种方式设计它?我觉得这是不一致的。什么是技术解释? –

+0

有批次的规则。其中之一是你不能改变表格,并在同一批次中引用新列,正如另一个答案中所述。情况1:创建表,这是允许的。情况2:表格被改变,这是不允许的。 – OzrenTkalcecKrznaric

+0

@SriwanthaSriAravinda:'编译错误'是**的技术解释。阅读文章链接了解技术解释。 –

1

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

See this

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

exec('select ft_ID from dbo.Products') 

然而,正如Remus说,必须非常小心混合模式更改并从该模式中选择数据,特别是在同一个事务中。即使没有事务,这段代码也会产生副作用:尝试在存储过程中包装这个exec()解决方法,并且每次调用它时都会得到重新编译。运气不好,但它只是这样工作。