如何停止 Sql Server 的用户实例? (Sql Express 用户实例数据库文件被锁定,即使在停止 Sql Express 服务后也是如此)

发布于 2024-08-23 04:29:56 字数 1354 浏览 2 评论 0原文

当使用带有如下连接字符串的 SQL Server Express 2005 的用户实例功能时:

<add name="Default" connectionString="Data Source=.\SQLExpress;
  AttachDbFilename=C:\My App\Data\MyApp.mdf;
  Initial Catalog=MyApp;
  User Instance=True;
  MultipleActiveResultSets=true;
  Trusted_Connection=Yes;" />

我们发现即使在停止 SqlExpress 服务后也无法复制数据库文件 MyApp.mdf 和 MyApp_Log.ldf (因为它们已被锁定),并且有将SqlExpress服务从自动启动模式设置为手动启动模式,然后重新启动机器,然后我们才能复制文件。

据我了解,停止 SqlExpress 服务也应该停止所有用户实例,这应该释放这些文件上的锁定。但情况似乎并非如此 - 谁能阐明如何停止用户实例,使其数据库文件不再被锁定?


更新

好吧,我不再偷懒了,而是启动了 Process Explorer。锁由 sqlserver.exe 持有 - 但有两个 sql server 实例:

sqlserver.exe  PID: 4680  User Name: DefaultAppPool
sqlserver.exe  PID: 4644  User Name: NETWORK SERVICE

文件由 PID 为 4680 的 sqlserver.exe 实例打开

停止“SQL Server (SQLEXPRESS)”服务,终止 PID 为的进程: 4644,但留下了 PID:4680。

由于剩余进程的所有者是 DefaultAppPool,我接下来尝试的是停止 IIS(该数据库正在从 ASP.Net 应用程序中使用)。不幸的是,这也没有终止该进程。

手动终止剩余的 sql server 进程确实会删除数据库文件上的打开文件句柄,从而允许复制/移动它们。

不幸的是,我希望在 WiX 安装程序的一些安装前/安装后任务中复制/恢复这些文件 - 因此我希望有一种方法可以通过停止 Windows 服务来实现此目的,而不是必须杀死所有实例sqlserver.exe 的问题,因为这会带来一些问题:

  1. 终止所有 sqlserver.exe 实例可能会给计算机上拥有其他 Sql Server 实例的用户带来不良后果。
  2. 我无法轻松重新启动这些实例。
  3. 给安装程序带来了额外的复杂性。

有谁对如何关闭与特定用户实例关联的 sql server 实例有任何进一步的想法吗?

When using SQL Server Express 2005's User Instance feature with a connection string like this:

<add name="Default" connectionString="Data Source=.\SQLExpress;
  AttachDbFilename=C:\My App\Data\MyApp.mdf;
  Initial Catalog=MyApp;
  User Instance=True;
  MultipleActiveResultSets=true;
  Trusted_Connection=Yes;" />

We find that we can't copy the database files MyApp.mdf and MyApp_Log.ldf (because they're locked) even after stopping the SqlExpress service, and have to resort to setting the SqlExpress service from automatic to manual startup mode, and then restarting the machine, before we can then copy the files.

It was my understanding that stopping the SqlExpress service should stop all the user instances as well, which should release the locks on those files. But this does not seem to be the case - could anyone shed some light on how to stop a user instance, such that it's database files are no longer locked?


Update

OK, I stopped being lazy and fired up Process Explorer. Lock was held by sqlserver.exe - but there are two instances of sql server:

sqlserver.exe  PID: 4680  User Name: DefaultAppPool
sqlserver.exe  PID: 4644  User Name: NETWORK SERVICE

The file is open by the sqlserver.exe instance with the PID: 4680

Stopping the "SQL Server (SQLEXPRESS)" service, killed off the process with PID: 4644, but left PID: 4680 alone.

Seeing as the owner of the remaining process was DefaultAppPool, next thing I tried was stopping IIS (this database is being used from an ASP.Net application). Unfortunately this didn't kill the process off either.

Manually killing off the remaining sql server process does remove the open file handle on the database files, allowing them to be copied/moved.

Unfortunately I wish to copy/restore those files in some pre/post install tasks of a WiX installer - as such I was hoping there might be a way to achieve this by stopping a windows service, rather then having to shell out to kill all instances of sqlserver.exe as that poses some problems:

  1. Killing all the sqlserver.exe instances may have undesirable consequencies for users with other Sql Server instances on their machines.
  2. I can't restart those instances easily.
  3. Introduces additional complexities into the installer.

Does anyone have any further thoughts on how to shutdown instances of sql server associated with a specific user instance?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浮萍、无处依 2024-08-30 04:29:56

使用“SQL Server Express 实用程序”(SSEUtil.exe) 或命令来分离 SSEUtil 使用的数据库。

SQL Server Express 实用程序,
SSEUtil 是一个可以让您轻松与 SQL Server 交互的工具,
http://www.microsoft .com/downloads/details.aspx?FamilyID=fa87e828-173f-472e-a85c-27ed01cf6b02&DisplayLang=en

另外,最后一次连接关闭后停止服务的默认超时时间为一小时。在您的开发盒上,您可能希望将其更改为五分钟(允许的最小值)。

此外,您可能通过 Visual Studio 的服务器资源管理器数据连接打开了连接,因此请务必断开与那里的任何数据库的连接。

H:\Tools\SQL Server Express Utility>sseutil -l
1. master
2. tempdb
3. model
4. msdb
5. C:\DEV_\APP\VISUAL STUDIO 2008\PROJECTS\MISSICO.LIBRARY.1\CLIENTS\CORE.DATA.C
LIENT\BIN\DEBUG\CORE.DATA.CLIENT.MDF

H:\Tools\SQL Server Express Utility>sseutil -d C:\DEV*
Failed to detach 'C:\DEV_\APP\VISUAL STUDIO 2008\PROJECTS\MISSICO.LIBRARY.1\CLIE
NTS\CORE.DATA.CLIENT\BIN\DEBUG\CORE.DATA.CLIENT.MDF'

H:\Tools\SQL Server Express Utility>sseutil -l
1. master
2. tempdb
3. model
4. msdb

H:\Tools\SQL Server Express Utility>

使用 .NET Refector,以下命令用于分离数据库。

string.Format("USE master\nIF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{0}')\nBEGIN\n\tALTER DATABASE [{1}] SET OFFLINE WITH ROLLBACK IMMEDIATE\n\tEXEC sp_detach_db [{1}]\nEND", dbName, str);

Use "SQL Server Express Utility" (SSEUtil.exe) or the command to detach the database used by SSEUtil.

SQL Server Express Utility,
SSEUtil is a tool that lets you easily interact with SQL Server,
http://www.microsoft.com/downloads/details.aspx?FamilyID=fa87e828-173f-472e-a85c-27ed01cf6b02&DisplayLang=en

Also, the default timeout to stop the service after the last connection is closed is one hour. On your development box, you may want to change this to five minutes (the minimum allowed).

In addition, you may have an open connection through Visual Studio's Server Explorer Data Connections, so be sure to disconnect from any database there.

H:\Tools\SQL Server Express Utility>sseutil -l
1. master
2. tempdb
3. model
4. msdb
5. C:\DEV_\APP\VISUAL STUDIO 2008\PROJECTS\MISSICO.LIBRARY.1\CLIENTS\CORE.DATA.C
LIENT\BIN\DEBUG\CORE.DATA.CLIENT.MDF

H:\Tools\SQL Server Express Utility>sseutil -d C:\DEV*
Failed to detach 'C:\DEV_\APP\VISUAL STUDIO 2008\PROJECTS\MISSICO.LIBRARY.1\CLIE
NTS\CORE.DATA.CLIENT\BIN\DEBUG\CORE.DATA.CLIENT.MDF'

H:\Tools\SQL Server Express Utility>sseutil -l
1. master
2. tempdb
3. model
4. msdb

H:\Tools\SQL Server Express Utility>

Using .NET Refector the following command is used to detach the database.

string.Format("USE master\nIF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{0}')\nBEGIN\n\tALTER DATABASE [{1}] SET OFFLINE WITH ROLLBACK IMMEDIATE\n\tEXEC sp_detach_db [{1}]\nEND", dbName, str);
漫漫岁月 2024-08-30 04:29:56

我一直在使用以下帮助程序方法在单元测试中分离附加到 SQL Server 的 MDF 文件(以便 SQ Server 释放 MDF 和 LDF 文件上的锁,并且单元测试可以自行清理)...

private static void DetachDatabase(DbProviderFactory dbProviderFactory, string connectionString)
{
    using (var connection = dbProviderFactory.CreateConnection())
    {
        if (connection is SqlConnection)
        {
            SqlConnection.ClearAllPools();

            // convert the connection string (to connect to 'master' db), extract original database name
            var sb = dbProviderFactory.CreateConnectionStringBuilder();
            sb.ConnectionString = connectionString;
            sb.Remove("AttachDBFilename");
            var databaseName = sb["database"].ToString();
            sb["database"] = "master";
            connectionString = sb.ToString();

            // detach the original database now
            connection.ConnectionString = connectionString;
            connection.Open();
            using (var cmd = connection.CreateCommand())
            {
                cmd.CommandText = "sp_detach_db";
                cmd.CommandType = CommandType.StoredProcedure;

                var p = cmd.CreateParameter();
                p.ParameterName = "@dbname";
                p.DbType = DbType.String;
                p.Value = databaseName;
                cmd.Parameters.Add(p);

                p = cmd.CreateParameter();
                p.ParameterName = "@skipchecks";
                p.DbType = DbType.String;
                p.Value = "true";
                cmd.Parameters.Add(p);

                p = cmd.CreateParameter();
                p.ParameterName = "@keepfulltextindexfile";
                p.DbType = DbType.String;
                p.Value = "false";
                cmd.Parameters.Add(p);

                cmd.ExecuteNonQuery();
            }
        }
    }
}

注意:

  • SqlConnection .ClearAllPools() 对于消除“隐形”连接非常有帮助(当连接被池化时,即使您“Close()”它,它也会保持活动状态;通过显式清除池连接,您不必担心关于在所有连接字符串中将池标志设置为 false)。
  • “神奇成分”是对系统存储过程的调用sp_detach_db (Transact-SQL)
  • 我的连接字符串包含“AttachDBFilename”,但不包含“User Instance=True”,因此此解决方案可能不适用于您的场景

I have been using the following helper method to detach MDF files attached to SQL Server in unit tests (so that SQ Server releases locks on MDF and LDF files and the unit test can clean up after itself)...

private static void DetachDatabase(DbProviderFactory dbProviderFactory, string connectionString)
{
    using (var connection = dbProviderFactory.CreateConnection())
    {
        if (connection is SqlConnection)
        {
            SqlConnection.ClearAllPools();

            // convert the connection string (to connect to 'master' db), extract original database name
            var sb = dbProviderFactory.CreateConnectionStringBuilder();
            sb.ConnectionString = connectionString;
            sb.Remove("AttachDBFilename");
            var databaseName = sb["database"].ToString();
            sb["database"] = "master";
            connectionString = sb.ToString();

            // detach the original database now
            connection.ConnectionString = connectionString;
            connection.Open();
            using (var cmd = connection.CreateCommand())
            {
                cmd.CommandText = "sp_detach_db";
                cmd.CommandType = CommandType.StoredProcedure;

                var p = cmd.CreateParameter();
                p.ParameterName = "@dbname";
                p.DbType = DbType.String;
                p.Value = databaseName;
                cmd.Parameters.Add(p);

                p = cmd.CreateParameter();
                p.ParameterName = "@skipchecks";
                p.DbType = DbType.String;
                p.Value = "true";
                cmd.Parameters.Add(p);

                p = cmd.CreateParameter();
                p.ParameterName = "@keepfulltextindexfile";
                p.DbType = DbType.String;
                p.Value = "false";
                cmd.Parameters.Add(p);

                cmd.ExecuteNonQuery();
            }
        }
    }
}

Notes:

  • SqlConnection.ClearAllPools() was very helpful in eliminating "stealth" connections (when a connection is pooled, it will stay active even though you 'Close()' it; by explicitely clearing pool connections you don't have to worry about setting pooling flag to false in all connection strings).
  • The "magic ingredient" is call to the system stored procedure sp_detach_db (Transact-SQL).
  • My connection strings included "AttachDBFilename" but didn't include "User Instance=True", so this solution might not apply to your scenario
我只土不豪 2024-08-30 04:29:56

我还不能发表评论,因为我还没有足够高的代表。有人可以将此信息移至其他答案,这样我们就不会被骗吗?

我只是用这篇文章来解决我的 WIX 卸载问题。我使用了 AMissico 的答案中的这句话。

string.Format("USE master\nIF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{0}')\nBEGIN\n\tALTER DATABASE [{1}] SET OFFLINE WITH ROLLBACK IMMEDIATE\n\tEXEC sp_detach_db [{1}]\nEND", dbName, str);

使用 WIX 时效果非常好,只需添加一件事即可使其适合我。

我取出了 sp_detach_db,然后将数据库重新联机。如果不这样做,WIX 将在卸载后保留 mdf 文件。一旦我将数据库恢复在线,WIX 就会正确删除 mdf 文件。

这是我修改后的线路。

string.Format( "USE master\nIF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{0}')\nBEGIN\n\tALTER DATABASE [{0}] SET OFFLINE WITH ROLLBACK IMMEDIATE\n\tALTER DATABASE [{0}] SET ONLINE\nEND", dbName );

I can't comment yet because I don't have high enough rep yet. Can someone move this info to the other answer so we don't have a dupe?

I just used this post to solve my WIX uninstall problem. I used this line from AMissico's answer.

string.Format("USE master\nIF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{0}')\nBEGIN\n\tALTER DATABASE [{1}] SET OFFLINE WITH ROLLBACK IMMEDIATE\n\tEXEC sp_detach_db [{1}]\nEND", dbName, str);

Worked pretty well when using WIX, only I had to add one thing to make it work for me.

I had took out the sp_detach_db and then brought the db back online. If you don't, WIX will leave the mdf files around after the uninstall. Once I brought the db back online WIX would properly delete the mdf files.

Here is my modified line.

string.Format( "USE master\nIF EXISTS (SELECT * FROM sysdatabases WHERE name = N'{0}')\nBEGIN\n\tALTER DATABASE [{0}] SET OFFLINE WITH ROLLBACK IMMEDIATE\n\tALTER DATABASE [{0}] SET ONLINE\nEND", dbName );
不再让梦枯萎 2024-08-30 04:29:56

这可能不是您想要的,但免费工具 Unlocker 有一个可以从 WIX 运行的命令行界面。 (我使用解锁器有一段时间了,发现它很稳定,并且非常擅长解锁文件。)

解锁器可以解锁和移动/删除大多数文件。

这样做的缺点是需要锁定文件的应用程序将不再拥有它。 (但有时仍然可以正常工作。)请注意,这不会杀死拥有锁的进程。它只是删除了它的锁。 (重新启动您正在停止的 sql 服务可能足以使其重新锁定和/或正常工作。)

您可以从这里获取 Unlocker:http://www.emptyloop.com/unlocker/

要查看命令行选项,请运行 unlocker -H
这里是为了方便起见:

Unlocker 1.8.8

Command line usage:
   Unlocker.exe Object [Option]
Object:
   Complete path including drive to a file or folder
Options:
   /H or -H or /? or -?: Display command line usage 
   /S or -S: Unlock object without showing the GUI 
   /L or -L: Object is a text file containing the list of files to unlock 
   /LU or -LU: Similar to /L with a unicode list of files to unlock 
   /O or -O: Outputs Unlocker-Log.txt log file in Unlocker directory 
   /D or -D: Delete file 
   /R Object2 or -R Object2: Rename file, if /L or /LU is set object2 points to a text file containing the new name of files 
   /M Object2 or -M Object2: Move file, if /L or /LU is set object2 points a text file containing the new location of files 

假设您的目标是用安装程序中的文件替换 C:\My App\Data\MyApp.mdf,您可能需要类似 unlocker C:\My App\Data\MyApp.mdf -S -D。这将删除该文件,以便您可以复制一个新文件。

This may not be what you are looking for, but the free tool Unlocker has a command line interface that could be run from WIX. (I have used unlocker for a while and have found it stable and very good at what it does best, unlocking files.)

Unlocker can unlock and move/delete most any file.

The downside to this is the apps that need a lock on the file will no longer have it. (But sometimes still work just fine.) Note that this does not kill the process that has the lock. It just removes it's lock. (It may be that restarting the sql services that you are stopping will be enough for it to re-lock and/or work correctly.)

You can get Unlocker from here: http://www.emptyloop.com/unlocker/

To see the command line options run unlocker -H
Here they are for convenience:

Unlocker 1.8.8

Command line usage:
   Unlocker.exe Object [Option]
Object:
   Complete path including drive to a file or folder
Options:
   /H or -H or /? or -?: Display command line usage 
   /S or -S: Unlock object without showing the GUI 
   /L or -L: Object is a text file containing the list of files to unlock 
   /LU or -LU: Similar to /L with a unicode list of files to unlock 
   /O or -O: Outputs Unlocker-Log.txt log file in Unlocker directory 
   /D or -D: Delete file 
   /R Object2 or -R Object2: Rename file, if /L or /LU is set object2 points to a text file containing the new name of files 
   /M Object2 or -M Object2: Move file, if /L or /LU is set object2 points a text file containing the new location of files 

Assuming your goal was to replace C:\My App\Data\MyApp.mdf with a file from your installer, you would want something like unlocker C:\My App\Data\MyApp.mdf -S -D. This would delete the file so you could copy in a new one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文