2013-10-31 30 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()解決方法,並且每次調用它時都會得到重新編譯。運氣不好,但它只是這樣工作。