응용 프로그램의 일부로 SQL Server Express 서비스에 프로그래밍 방식으로 액세스해야합니다. 사용자가하려는 작업에 따라 데이터베이스를 연결하거나 데이터베이스를 분리하거나 백업해야 할 수도 있습니다. 이러한 작업을 시도하기 전에 서비스가 시작되지 않을 수도 있습니다. 따라서 우리는 서비스가 시작되었는지 확인해야합니다. 여기 우리가 문제를 겪고있는 곳이 있습니다. 분명히 ServiceController.WaitForStatus(ServiceControllerStatus.Running)
은 SQL Server Express에 대해 조기에 반환됩니다. 정말 수수께끼 같은 점은 마스터 데이터베이스는 즉시 사용할 수 있지만 다른 데이터베이스는 사용할 수없는 것입니다. 여기에 내가 말하고있는 것을 보여주기위한 콘솔 응용 프로그램이 있습니다 :시작된 서비스가 시작한 서비스는 언제입니까? (SQL Express)
namespace ServiceTest
{
using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
class Program
{
private static readonly ServiceController controller = new ServiceController("MSSQL$SQLEXPRESS");
private static readonly Stopwatch stopWatch = new Stopwatch();
static void Main(string[] args)
{
stopWatch.Start();
EnsureStop();
Start();
OpenAndClose("master");
EnsureStop();
Start();
OpenAndClose("AdventureWorksLT");
Console.ReadLine();
}
private static void EnsureStop()
{
Console.WriteLine("EnsureStop enter, {0:N0}", stopWatch.ElapsedMilliseconds);
if (controller.Status != ServiceControllerStatus.Stopped)
{
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped);
Thread.Sleep(5000); // really, really make sure it stopped ... this has a problem too.
}
Console.WriteLine("EnsureStop exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
private static void Start()
{
Console.WriteLine("Start enter, {0:N0}", stopWatch.ElapsedMilliseconds);
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running);
// Thread.Sleep(5000);
Console.WriteLine("Start exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
private static void OpenAndClose(string database)
{
Console.WriteLine("OpenAndClose enter, {0:N0}", stopWatch.ElapsedMilliseconds);
var connection = new SqlConnection(string.Format(@"Data Source=.\SQLEXPRESS;initial catalog={0};integrated security=SSPI", database));
connection.Open();
connection.Close();
Console.WriteLine("OpenAndClose exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
}
}
내 컴퓨터에서 이것은 일관되게 서면으로 실패합니다. "master"와의 연결에는 문제가 없습니다. 다른 데이터베이스에 대한 연결 만. 연결 확인을 위해 연결 순서를 반대로 할 수 있습니다. Start()
메서드에서 Thread.Sleep
의 주석을 제거하면 올바르게 작동합니다.
분명히 나는 임의의 것을 피하고자한다. Thread.Sleep()
. 랭크 코드 냄새 외에, 내가 임의의 가치를 부여 할 수 있을까요? 우리가 생각할 수있는 유일한 방법은 while 루프에서 대상 데이터베이스에 더미 연결을 설정하고 throw 된 SqlException을 catch 한 다음 작동 할 때까지 다시 시도하는 것입니다. 그러나 서비스가 실제로 사용될 준비가되었는지를 알기 위해보다 세련된 솔루션이 있어야한다고 생각합니다. 어떤 아이디어?
편집 : 아래에 제공된 피드백을 기반으로 데이터베이스의 상태를 확인했습니다. 그러나 여전히이 실패했습니다. 그것은 심지어 상태가 신뢰할 수없는 것처럼 보입니다.
private static void WaitForOnline(string database)
{
Console.WriteLine("WaitForOnline start, {0:N0}", stopWatch.ElapsedMilliseconds);
using (var connection = new SqlConnection(string.Format(@"Data Source=.\SQLEXPRESS;initial catal
using (var command = connection.CreateCommand())
{
connection.Open();
try
{
command.CommandText = "SELECT [state] FROM sys.databases WHERE [name] = @DatabaseName";
command.Parameters.AddWithValue("@DatabaseName", database);
byte databaseState = (byte)command.ExecuteScalar();
Console.WriteLine("databaseState = {0}", databaseState);
while (databaseState != OnlineState)
{
Thread.Sleep(500);
databaseState = (byte)command.ExecuteScalar();
Console.WriteLine("databaseState = {0}", databaseState);
}
}
finally
{
connection.Close();
}
}
Console.WriteLine("WaitForOnline exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
나는 비슷한 문제를 다루는 another discussion을 발견 : 여기 OpenAndClose (문자열) 전에 호출하고있는 기능입니다. 분명히 해결책은 해당 데이터베이스의 sys.database_files를 확인하는 것입니다. 그러나 그것은 물론 닭고기 및 달걀 문제입니다. 다른 아이디어?
온라인에 대한 수표를 추가했습니다. 그것은 여전히 실패하고 있습니다. : 필자는 원래의 게시물을 편집하고 sys_database_files에 대한 주석을 추가로 편집했습니다. –
서비스 시작 후 마스터에 연결할 수 있으므로 대상 데이터베이스 상태를 확인하고 온라인 상태입니다 , 아직 초기 db 대상 데이터베이스를 지정하는 연결을 열려고 할 때 여전히 실패합니다. 오류가있는 오류가 있습니까? ADO.Net 연결 풀링이이 시나리오를 방해 할 수 있는지 이해하려고 해요 (shouldn 't,하지만 하나는 결코 알지 못합니다 ...) db가 ONLINE이라도 conenciton이 여전히 오류를 throw하면 실제로 시도가 성공할 때까지는 try/catch 루프 이외의 해결책이 표시되지 않습니다. –