2015-12-15 42 views
0

我正在做一些遠程sql server數據庫的工作,需要一些時間,我需要阻止任何其他連接到它,所以沒有數據丟失 我相信我應該使用單用戶模式下做到這一點如何在一個TRANSACTION內執行ALTER DATABASE在SqlServer中

我需要得到它回到多用戶模式後,我完成我的工作,但 我到遠程服務器連接不可靠,很多時候會結束之前斷開連接,通常只是回滾自動以後再做 問題是當我嘗試在交易中執行它時,我得到這個錯誤:

ALTER DATABASE語句不在事務多語句事務

我怎麼能執行

ALTER DATABASE dbName 
SET SINGLE_USER WITH ROLLBACK IMMEDIATE 

內允許和確保如果斷開了它會回滾到多用戶模式?

+2

詢問如何能夠*完全*錯誤已告訴你不可能的事情似乎不是很明智。如果您的實際目標是您最終陳述的內容,則可能存在其他可行的策略 - 將數據庫作爲某種形式的故障安全恢復到多用戶模式。 (例如,在開始工作之前設置一個適當的工作計劃以更改數據庫) –

+0

@Damien_The_Unbeliever我顯然是在尋找圍繞 –

回答

1

所以,如果我們的連接斷開,我們正試圖安排一個數據庫返回到multi_user模式。 的工作方式如下,但與罪惡一樣醜陋。

首先,我們適當地做一些事情,:

create database RevertTest 
go 
use master 
go 
create table RevertLock (L int not null) 
go 
declare @rc int 
declare @job_id uniqueidentifier 

exec @rc = msdb..sp_add_job @job_name='RevertSingleUser', 
          @description='Revert the RevertTest database to multi_user mode', 
          @delete_level=3, 
          @job_id = @job_id OUTPUT 

if @rc != 0 goto Failed 

exec @rc = msdb..sp_add_jobstep @job_id = @job_id, 
           @step_name = 'Wait to revert', 
           @command = ' 
WHILE EXISTS (SELECT * FROM RevertLock) 
    WAITFOR DELAY ''00:00:01'' 

ALTER DATABASE RevertTest set multi_user 

DROP TABLE RevertLock' 
if @rc != 0 goto Failed 

declare @nowish datetime 
declare @StartDate int 
declare @StartTime int 

set @nowish = DATEADD(minute,30,GETDATE()) 
select @StartDate = DATEPART(year,@nowish) * 10000 + DATEPART(month,@nowish) * 100 + DATEPART(day,@nowish), 
     @StartTime = DATEPART(hour,@nowish) * 10000 + DATEPART(minute,@nowish) * 100 + DATEPART(second,@nowish) 

exec @rc = msdb..sp_add_jobschedule @job_id = @job_id, 
            @name='Failsafe', 
            @freq_type=1, 
            @active_start_date = @StartDate, 
            @active_start_time = @StartTime 
if @rc != 0 goto Failed 

exec @rc = msdb..sp_add_jobserver @job_id = @job_id 
if @rc != 0 goto Failed 

print 'Good to go!' 
goto Fin 
Failed: 
print 'No good - couldn''t establish rollback plan' 
Fin: 

基本上,我們創建了以後我們收拾工作。我們安排這項工作在半小時內開始運行,但這只是爲了保護我們免受小規模的比賽。

我們現在運行我們的實際腳本做到這一點,以我們想要的工作:

use RevertTest 
go 
alter database RevertTest set single_user with rollback immediate 
go 
begin transaction 
go 
insert into master..RevertLock(L) values (1) 
go 
exec msdb..sp_start_job @job_name='RevertSingleUser' 
go 
WAITFOR DELAY '01:00:00' 

如果您運行此腳本,你就可以觀察到該數據庫已經進入單用戶模式 ​​- 最後的WAITFOR DELAY只是爲了模擬我們「做工作」 - 無論您希望在數據庫中執行單個用戶模式的操作。如果您停止運行該查詢斷開此查詢窗口,在一秒鐘內您應該看到數據庫已返回到multi_user模式。

要成功完成腳本,只需從RevertLock表中刪除最後一個任務(在COMMIT之前)即可。與斷開連接一樣,恢復作業將負責將DB切換回multi_user,然後自行清理。


的工作實際上是略有欺騙性。它實際上不會在循環中檢查主表中的表 - 因爲您的事務由於INSERT而具有排它鎖。它會坐下來耐心地等待獲得合適的鎖定,這隻有在您的交易提交或回滾時纔會發生。

+0

感謝您的努力,這是一個很好的答案,但我仍然無法使用它,因爲我正在使用sql express。所以沒有工作 –

+0

如果沒有任何其他答案,這應該被認爲是正確的答案 –

+0

@ M.Sabaa - 是的,對不起,這對於Express來說並不容易。這個答案的本質是「讓代碼在獨立的上下文中運行」 - 而且Express並沒有直接的方法。我偶爾通過安裝不會終止的啓動程​​序來完成「分類」作業,只是等到一天的正確時間才能開始工作 - 但是這需要您能夠重新啓動服務,並且它不太合適爲了這裏的任務。 –

1

您不能在事務中包含ALTER語句。但是你可以頂部和尾部的交易,就像這樣:

ALTER DATABASE TEST SET SINGLE_USER 
GO 

    BEGIN TRANSACTION 

     -- Generate an error. 
     SELECT 1/0 


    ROLLBACK TRANSACTION 

GO 
ALTER DATABASE TEST SET MULTI_USER 

此腳本設置數據庫爲單用戶模式。然後在返回多用戶模式之前遇到錯誤。

+0

的工作當我的服務器連接斷開連接時, –

+0

我建議看看Damien_The_Unbeliever的回答。 –

相關問題