2009-06-25 75 views
7

我有一个使用两个数据库的Web应用程序。 DB1用户执行他们的CRUD(创建,读取,更新,删除)操作。数据库DB2是用于报告目的的不同服务器上的只读数据库。每个小时,我的DB1都会保存事务日志,而在DB2上,我有一份工作可以在DB2上恢复它们​​以保持它最新。在恢复SQL Server数据库之前等待连接关闭

我面临的问题是,如果有用户在DB2上运行报告(经常发生),他们会从sql服务器断开连接,因为我获得了独占访问来还原数据库。恢复每个日志所需的时间范围在1-4分钟之间。

我该如何实现让我们称之为等待 - 恢复功能,其中我的作业等待用户的查询完成,然后再将数据库切换到独占访问并恢复日志?

我的机器上运行两个SQL Server 2008中的64位标准版

回答

2

重要组成部分我的问题是使用池连接 - 在这种情况下,即使没有报告执行连接保持活着。我修改了我的连接字符串,将连接池设置为false,并在循环中检查与报表DB的开放用户连接,直到值为0.幸运的是,我不必创建触发器来将用户关闭。

1

你可能有一个ALTER DATABASE设置有单个用户或管理员模式下的“立即ROLLBACK”在里面。这就是踢出用户的原因。拿出这个条款,它会等待他们离开(但不会阻止新来的)。

RE:你杀死sProc:你可能想看看“WITH IMMEDIATE ROLLBACK”选项。

至于阻止新连接:我过去所做的是禁用应用程序用户的登录(服务器主体),等待长达10分钟检查每分钟,看看是否每个人都在外面。之后,我执行ALTER DATABASE ...以立即ROLLBACK,然后进入任何需要执行的OPS功能。

我一直很幸运,登录总是一次性使用应用程序用户登录(即SQL登录仅用于此目的)如果您不能这样做,那么我现在唯一可以考虑的其他事情将拒绝对DB用户(数据库主体)的CONNECT权限。然后再去掉DENY。我从来没有这样做过,但它应该像这样:

DENY CONNECT TO SomeDBUserName; 
+0

我acctually使用存储的过程,踢大家出: ALTER PROCEDURE [DBO] [USP_GETEXCLUSIVE] @dbname VARCHAR(100)AS DECLARE @KILL_ID INT DECLARE VARCHAR @QUERY(320) DECLARE GETEXCLUSIVE_CURSOR CURSOR FOR SELECT A.SPID FROM SYSPROCESSES A JOIN SYSDATABASES乙ON A.DBID = B.DBID WHERE [email protected] OPEN GETEXCLUSIVE_CURSOR FETCH NEXT FROM GETEXCLUSIVE_CURSOR INTO @KILL_ID WHILE(@@ FETCH_STATUS = 0) BEGIN SET @QUERY ='KIL L“+ CONVERT(VARCHAR,@ KILL_ID) EXEC(@QUERY) NEXT来去GETEXCLUSIVE_CURSOR INTO @KILL_ID END CLOSE GETEXCLUSIVE_CURSOR DEALLOCATE GETEXCLUSIVE_CURSOR – lstanczyk 2009-06-25 19:13:37

+0

最大的问题是如何不要让数据库接受的时间,而新的连接我在等。 – lstanczyk 2009-06-25 19:14:31

0

报告可以重定向到不同的数据库名称吗?如果是,则可以创建DB2的数据库快照,并从这些快照运行报告。在每次日志恢复后,您都会创建一个新快照,并将其标记为'当前快照',并且所有新报告都将开始针对此快照运行。在发布新日志时,会创建一个新快照,并且新的报告将违背新的快照,而旧的正在运行的报告将保留在上一个快照中。当上次报告与旧快照一起完成并且不再有用户引用它时,它可以被删除。这样就不会中断任何报告,但需要额外的存储空间:每个新日志都会导致旧快照开始执行受影响页面的“写时复制”操作。

0

备份是否需要每隔一小时进行一次,或者另一种复制方法是否比您设置的自定义流程更好地满足您的需求?你可以做日志传送,它可以配置为每隔一小时发送一次,而SQL Server会自然处理它,在日志恢复时阻止用户。

我可以看到你的问题,我不认为SQL Server具有你正在寻找的功能(阻止新的连接,同时允许现有的连接完成),但还有其他的解决方法,可以让你相同的复制功能,可能会更好地完成业务需求。

1

我认为你的恢复是作为一项工作发生的。那么你需要的是一个登录触发器。这里是你如何创建一个登录触发器:

登录触发器

登录触发器时将触发建立会话。此时会引发LOGON事件。

登录触发器的生命周期非常简单:用户连接到Sql Server,触发器触发,隐式事务打开,然后由您决定!如果出于任何原因想要拒绝登录到Sql Server的尝试,只需发出ROLLBACK语句即可完成。

下面是一个简单的登录触发器:

USE master; 
GO 
CREATE LOGIN security_login WITH PASSWORD = '[email protected]'; 
GO 
GRANT VIEW SERVER STATE TO security_login; 
GO 
CREATE TRIGGER connection_deny_trigger 
ON ALL SERVER WITH EXECUTE AS 'security_login' 
FOR LOGON 
AS 
BEGIN 
<*Your conditional code goes here*> 
    ROLLBACK; 
END; 

你可以定义你的工作要做到这一点:

  • 步骤1:启用登录触发器
  • 第2步:检查是否有打开的用户 连接到您的报告数据库 循环中,直到值为0

    SELECT COUNT(*) from sysprocesses where spid in(
    SELECT session_id FROM sys.dm_exec_sessions WHERE is_user_process = 1) AND 
    dbid= DB_ID('YourReportingDatabase') 
    
  • 第3步:设置数据库为单用户和 恢复日志

  • 步骤4:将DB到多用户和禁用登录触发器

拉吉