3

アプリケーションの簡単なデータベースのバックアップと復元のルーチンを作成しています。データベースを問題なくバックアップできますが、復元するとデータベースへの排他的アクセスを取得できません。

私はSOの修正のすべての組み合わせを試し、シングルユーザーモードにし、オフラインにしてから元に戻すだけで成功しません。スタジオマネージャー(エクスプレス)内でデータベースを正常に復元できます

現時点では、この方法がSQLサーバーへの唯一の接続であるため、復元を実行できない理由がわかりません。

問題がどこにあるかを指摘する助けに感謝します。

internal void RestoreDatabase(string databaseFile)
        {
            //get database details
            var databaseConfiguration = new DatabaseConfiguration().GetDatabaseConfiguration();

            try
            {
                //construct server connection string
                var connection = databaseConfiguration.IsSqlAuthentication
                                     ? new ServerConnection(databaseConfiguration.ServerInstance,
                                                            databaseConfiguration.SqlUsername,
                                                            databaseConfiguration.SqlPassword)
                                     : new ServerConnection(databaseConfiguration.ServerInstance);

                //set database to single user and kick everyone off
                using (
                    var sqlconnection =
                        new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
                {
                    sqlconnection.Open();
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Single_User WITH Rollback IMMEDIATE",
                                                        sqlconnection))
                    {                       
                        sqlcommand.ExecuteNonQuery();                        
                    }
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET OFFLINE",
                                                        sqlconnection))
                    {
                        sqlcommand.ExecuteNonQuery();
                    }
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE  " + databaseConfiguration.DatabaseName + "  SET ONLINE",
                                                        sqlconnection))
                    {
                        sqlcommand.ExecuteNonQuery();
                    }
                    sqlconnection.Close();
                }

                //setup server connection and restore
                var server = new Server(connection);
                var restore = new Restore();
                restore.Database = databaseConfiguration.DatabaseName;
                restore.Action = RestoreActionType.Database;
                restore.Devices.AddDevice(databaseFile, DeviceType.File);
                restore.ReplaceDatabase = true;
                restore.Complete += Restore_Complete;
                restore.SqlRestore(server);
            }
            catch (Exception ex)
            {
                //my bad
                restoreDatabaseServerError(ex.InnerException.Message, EventArgs.Empty);
            }
            finally
            {
                //set database to multi user
                using (
                    var sqlconnection =
                        new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
                {
                    sqlconnection.Open();
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Multi_User",
                                                        sqlconnection))
                    {
                        sqlcommand.ExecuteNonQuery();
                        sqlcommand.Dispose();
                    }
                    sqlconnection.Close();
                }
            }

        }
4

2 に答える 2

3

誰かがデータベースに接続している場合、SQL Serverはデータベースを削除できないため、試したように、既存の接続を切断する必要があります。single_userの問題は、それでも1人のユーザーが接続できることです。データベースをドロップすると、データベースに接続できないため、データベースから抜け出す必要があります。それは他の誰かが接続するためにそのスロットを開き、次にあなたがそれを落とすことを防ぎます。

その一瞬でデータベースに接続するのに特に優れているSQLServerプロセスがいくつかあります。レプリケーションはその一例です。(とにかく公開されているデータベースを実際に削除するべきではありません。別の話です。)

では、これについて何ができるでしょうか?100%安全な唯一の方法は、ユーザーがデータベースに接続できないようにすることです。唯一の実用的な方法は、データベースをオフラインに切り替えてから削除することです。ただし、これには厄介な副作用があり、SQL Serverはそのデータベースのファイルを削除しないため、手動で削除する必要があります。

もう1つのオプションは、十分に高速にすることです。あなたの例では、データベースを削除する前にデータベースをオンラインに戻します。これはかなりリソースを大量に消費するプロセスであり、「侵入者」が接続するのに多くの時間を与えます。

私が成功して使用しているソリューションは次のようになります。

ALTER DATABASE MyDb SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE;
USE MyDb;
ALTER DATABASE MyDb SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
USE tempdb;
DROP DATABASE MyDb;

これにより、最初にデータベースが制限付きユーザーに設定され、データベースに接続されます。次に、接続したまま、データベースをシングルユーザーに設定します。その後、コンテキストはtempdbに切り替えられ、その直後にドロップが実行されます。ここで重要なのは、これらのコマンドを1つのバッチとしてSQL Serverに送信して、USE tempdb;との間の時間を最小限に抑えることDROPです。最初にデータベースを制限付きユーザーに設定すると、まれなエッジケースが発生する可能性があるため、一見意味がない場合でも、データベースをそのままにしておきます。

これはまだ他の誰かが入るための理論的なギャップを残していますが、私はそれが失敗するのを見たことがありません。

データベースが削除された後、通常どおりに復元を実行できます。

幸運を。

于 2013-03-19T23:04:10.693 に答える
0

復元は、DBサーバーをシングルユーザーモードに設定したのと同じ接続で実行する必要があります。

以下の変更の要約として、使用の終わりを復元コードの下に移動し、SQL接続のクローズを復元後に移動して、同じ接続を使用するようにしました。また、不要なため、オフラインとオンラインのセットを削除しました。現在テストできませんので、動作するかどうかお知らせください。

  //set database to single user and kick everyone off
  using (var sqlconnection = new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
  {
    sqlconnection.Open();
    using (var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Single_User WITH Rollback IMMEDIATE",sqlconnection))
    {
        sqlcommand.ExecuteNonQuery();                        
    }
    //setup server connection and restore
    var server = new Server(sqlconnection);
    var restore = new Restore();
    restore.Database = databaseConfiguration.DatabaseName;
    restore.Action = RestoreActionType.Database;
    restore.Devices.AddDevice(databaseFile, DeviceType.File);
    restore.ReplaceDatabase = true;
    restore.Complete += Restore_Complete;
    restore.SqlRestore(server);
    sqlconnection.Close();
  }
于 2013-03-19T23:03:50.450 に答える