我正在远程sql server数据库上做一些工作需要一些时间,我需要阻止任何其他连接,所以没有数据丢失 我相信我应该使用单用户模式来做到这一点
我完成工作后需要将其恢复到多用户模式,但是 我与远程服务器的连接不可靠,很多时候会在完成之前断开连接,通常只是自动回滚并稍后再进行 问题是当我尝试在事务中执行它时我得到这个错误:
多语句事务中不允许使用ALTER DATABASE语句
我该怎么做
ALTER DATABASE dbName
SET SINGLE_USER WITH ROLLBACK IMMEDIATE
在一个事务中,如果断开连接,确保它将回滚到多用户模式?
答案 0 :(得分:2)
因此,如果连接断开,我们会尝试安排数据库返回到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
模式。
要成功完成脚本,只需从COMMIT
表中删除最后一个任务(在RevertLock
之前)。与断开连接一样,恢复作业 1 将负责将数据库切换回multi_user
,然后自行清理。
1 这项工作实际上有点欺骗性。它实际上不会循环并检查master中的表 - 因为您的事务由于INSERT
而对其进行了独占锁定。相反,它会坐下来并耐心地等待获得一个合适的锁,这只会在您的交易提交或回滚时发生。
答案 1 :(得分: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
此脚本将db设置为单用户模式。然后在返回多用户模式之前遇到错误。