我经常在恢复数据库的时候遇到一个问题,总是有程序自动连接到数据库,导致恢复失败。就算kill掉这些连接,这些程序也很快就重试然后再次连接上来,前后也就几秒的时间(说到这儿就想骂开发的)。
为了解决这个问题,做了一些研究。解决方法有:
1, 尽可能快的kill掉所有的connection然后restore
See Kill All Active Connections To A Database.
The reason that the approach that Adam suggested won't work is that during the time that you are looping over the active connections new one can be established, and you'll miss those. The article I linked to uses the following approach which does not have this drawback:
2,或者直接take DB offlline,然后再online。然后抓紧时间restore。
USE master
GO
ALTER DATABASE YourDatabaseName
SET OFFLINE WITH ROLLBACK IMMEDIATE
GO
3,上面两种方法都是抓紧时间才行。。。如果程序重试的实在太快,就可以take DB to single user mode。 这也是官方推荐的做法。
-- set your current connection to use master otherwise you might get an error
use master
ALTER DATABASE YourDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--do you stuff here
ALTER DATABASE YourDatabase SET MULTI_USER
这种方法的局限是,你取得了数据库的唯一一个链接,然后在query windows里做操作。这意味着你只能使用sql,如果你使用ssms的图形界面来restore,由于背后实际ssms会重新build connection到数据库,所以在单用户模式下是会失败的。这也意味着用第三方工具恢复数据库也是不可能的。不过像Litespeed这种第三方工具一般都会有一个选项,restore的时候可以先自动kill current processes,因此对于这种第三方工具是不需要用单用户模式的。
4,这还有一个更靠谱的方法,但也不是万能的。DBA的命真苦啊。。。
找到程序连接server的login,将该login映射到要恢复的数据库的user删除掉。这样程序就无法自动连接到数据库了。
缺点就是对于具有sysadmin role的用户是无法限制它的权限的。如果临时去掉sysadmin,则该login对其他数据库的操作也会被影响,而我们只希望影响发生在当前我们要restore的数据库。
不过在开发环境下,这么做不会有什么大问题。甚至暂时disable login也是可以的,因为即使disable login,程序正在使用的connection也不会断掉,只是不能建立新的connection。因此该login对其他数据库的使用不会受太大影响。此时就可以赶紧开始restore,一但restore开始,就可以enable login而不必等到restore结束,因为restore已经独占了数据库。
不过在production上还是不敢这么做啊。
不知道还有没有其他的好方法。我搜索了一下,在数据库级别限制访问ip是不可能的。