简体   繁体   English

C#如何检查数据库是否不忙?

[英]C# how to check if database is not busy?

My class has a couple of methods going on. 我班上有几种方法。 The first one is creating a database, that's done. 第一个是创建一个数据库,完成了。 Then, creates stored procedures that is being read from a sql file. 然后,创建从sql文件中读取的存储过程。 then detach that DB. 然后分离那个DB。 Now it seems that my store procedure query is taking a while to finish and my method to detach is being invoked while the database is busy. 现在看来我的存储过程查询需要一段时间才能完成,并且在数据库繁忙时调用我的分离方法。 So how do I tell if the database is idle. 那么我该如何判断数据库是否空闲。 The exception goes "cannot detach the database because it is currently in use" 例外是“无法分离数据库,因为它当前正在使用”

Methods: 方法:

void CreateStoredProcedures(string type)
        {
            string spLocation = File.ReadAllText("CreateStoredProcedures.sql");
            var conn = new SqlConnection(connectionString + ";database=" + type + DateTime.Now.ToString("yyyyMMdd"));            

            try
            {
                Server server = new Server(new ServerConnection(conn));
                server.ConnectionContext.ExecuteNonQuery(spLocation);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

bool DetachBackup(string type)
        {
            var conn = new SqlConnection(connectionString);
            SqlCommand command = new SqlCommand("", conn);
            command.CommandText = @"sys.sp_detach_db '" + type + DateTime.Now.ToString("yyyyMMdd") + "'";

            try
            {
                conn.Open();
                command.ExecuteNonQuery();

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return false;
            }
            finally
            {
                if ((conn.State == ConnectionState.Open))
                {
                    conn.Close();
                }
            }
            return true;
        }

Click event: 点击事件:

private void btnFullBackup_Click(object sender, EventArgs e)
        {
            lblStatus.Text = "Starting full backup...";
            Execute("FULL");
            progressBar.Value = 20;                       
            lblStatus.Text = "Copying tables...";
            progressBar.Value = 60;            
            CopyTables("FULL");
            progressBar.Value = 70;
            lblStatus.Text = "Creating stored procedures...";
            CreateStoredProcedures("FULL");

            progressBar.Value = 80;
            CheckDBSize(newBackupLocation, "FULL");

            progressBar.Value = 100;
            MessageBox.Show("Backup was created successfully", "",
                                MessageBoxButtons.OK, MessageBoxIcon.Information);            

            lblStatus.Text = "Done";
            progressBar.Value = 0;

            if (DetachBackup("FULL") == false)
            {
                DetachBackup("FULL");
            }
        }

Chances are it's getting hung on its own connection. 它可能会挂在它自己的连接上。 sp_detach_db's MSDN https://msdn.microsoft.com/en-CA/library/ms188031.aspx has the following suggestion under the section Obtain Exclusive Access: sp_detach_db的MSDN https://msdn.microsoft.com/en-CA/library/ms188031.aspx在获取独占访问权限部分下面有以下建议:

USE master; 
ALTER DATABASE [DBName] SET SINGLE_USER;

You're DetachBackup method will have connect to master, run the ALTER and the sp_detach_db procedure. 你的DetachBackup方法将连接到master,运行ALTER和sp_detach_db过程。

You aren't closing the connection in your CreateStoredProcedures method. 您没有在CreateStoredProcedures方法中关闭连接。 Put using statements in like I've shown here and it should fix the problem. 像我在这里展示的那样使用语句,它应该解决问题。 ( Brief using statement explanation from Microsoft. ) 简要使用Microsoft的声明解释。

Try this code for your methods: 尝试使用此代码的方法:

    void CreateStoredProcedures(string type)
    {
        string spLocation = File.ReadAllText("CreateStoredProcedures.sql");
        using (var conn = new SqlConnection(connectionString + ";database=" + type + DateTime.Now.ToString("yyyyMMdd")))
        {
            try
            {
                Server server = new Server(new ServerConnection(conn));
                server.ConnectionContext.ExecuteNonQuery(spLocation);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        } // End of using, connection will always close when you reach this point.
    }

    bool DetachBackup(string type)
    {
        using (var conn = new SqlConnection(connectionString))
        {
            SqlCommand command = new SqlCommand(@"sys.sp_detach_db '" + type + DateTime.Now.ToString("yyyyMMdd") + "'", conn);

            try
            {
                conn.Open();
                command.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return false;
            }
        } // End of using, connection will always close when you reach this point.
        return true;
    }

You shouldn't think of it as the database being "busy", but the error message uses good verbage: in use . 您不应该将其视为数据库“忙碌”,但错误消息使用良好的verbage: 正在使用中 To find out if the database is currently in use, the most accurate way would be to find out if any sessions have any lock in the particular database, by querying sys.dm_tran_locks . 要确定数据库当前是否正在使用,最准确的方法是通过查询sys.dm_tran_lockssys.dm_tran_locks特定数据库中是否存在任何锁定。 Here is a helper function to return a bool whether or not the database is in use: 这是一个帮助函数,无论数据库是否正在使用,都返回bool

    bool IsDatabaseInUse(string databaseName)
    {
        using (SqlConnection sqlConnection = new SqlConnection("... your connection string ..."))
        using (SqlCommand sqlCmd = new SqlCommand())
        {
            sqlCmd.Connection = sqlConnection;
            sqlCmd.CommandText =
                @"select count(*)
                from sys.dm_tran_locks
                where resource_database_id = db_id(@database_name);";
            sqlCmd.Parameters.Add(new SqlParameter("@database_name", SqlDbType.NVarChar, 128)
            {
                Value = databaseName
            });

            sqlConnection.Open();
            int sessionCount = Convert.ToInt32(sqlCmd.ExecuteScalar());

            if (sessionCount > 0)
                return true;
            else
                return false;
        }
    }

Note: Make sure your initial catalog in your connection string isn't the database you're trying to make "not in use", as that'll put your current session in the context of the database, not allowing that operation to complete 注意:确保连接字符串中的初始目录不是您尝试“未使用”的数据库,因为它会将您当前的会话置于数据库的上下文中,而不允许该操作完成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM