2010-03-02 4 views
6

Quando si utilizza SQL Server Express 2005 di funzione User Instance con una stringa di connessione come questo:Come si interrompe un'istanza utente di Sql Server? (File di database istanza utente SQL Express bloccati, anche dopo l'arresto SQL Express service)

<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;" /> 

Troviamo che non possiamo copiare il file di database MyApp.mdf e MyApp_Log.ldf (perché sono bloccati) anche dopo aver arrestato il servizio SqlExpress e devono ricorrere all'impostazione del servizio SqlExpress dalla modalità di avvio automatico a manuale, quindi riavviare la macchina, prima di poter copiare i file.

Sono stato a conoscenza del fatto che l'arresto del servizio SqlExpress dovrebbe interrompere anche tutte le istanze utente, che dovrebbero rilasciare i blocchi su tali file. Ma questo non sembra essere il caso - qualcuno potrebbe far luce su come fermare un'istanza utente, in modo tale che i suoi file di database non siano più bloccati?


Aggiornamento

OK, ho smesso di essere pigro e sparato su Process Explorer. Blocco è stata tenuta da sqlserver.exe - ma ci sono due istanze di SQL Server:

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

Il file è aperto dall'istanza sqlserver.exe con il PID: 4680

Arresto del "SQL Server (SQLEXPRESS) "servizio, ucciso dal processo con PID: 4644, ma lasciato PID: 4680 da solo.

Visto che il proprietario del processo rimanente era DefaultAppPool, la prossima cosa che ho provato è stata l'arresto di IIS (questo database viene utilizzato da un'applicazione ASP.Net). Sfortunatamente questo non ha eliminato il processo.

L'eliminazione manuale del processo del server sql rimanente rimuove l'handle di file aperto sui file di database, consentendo di copiarli/spostarli.

Sfortunatamente, desidero copiare/ripristinare quei file in alcune attività di installazione pre/post di un programma di installazione di WiX - come tale speravo che ci potesse essere un modo per ottenere ciò arrestando un servizio di Windows, piuttosto che doverlo sborsare per uccidere tutte le istanze di sqlserver.exe come quella pone alcuni problemi:

  1. uccidendo tutte le istanze sqlserver.exe possono avere consequencies indesiderabili per gli utenti con altre istanze di SQL Server sulle loro macchine.
  2. Impossibile riavviare facilmente tali istanze.
  3. Introduce ulteriori complessità nell'installer.

Qualcuno ha ulteriori informazioni su come arrestare le istanze di SQL Server associate a un'istanza utente specifica?

+0

AThanks per le risposte tutte - la risposta più utile è stata utilizzare SSEUtil.exe. Anche se abbiamo bisogno di invocare questo da un programma di installazione WiX, possiamo vedere che sarà un po 'problematico, cioè se l'utente che esegue il programma di installazione non ha le autorizzazioni per eseguire uno sp_dettach_db che è un problema indipendentemente dal metodo che usiamo - quindi potremmo è sufficiente fornire alcuni passaggi manuali di pre-installazione per gli utenti prima dell'aggiornamento, in modo che possano gestirli autonomamente utilizzando SSEUtil.exe. – Bittercoder

+0

Sono curioso, SSEUtil.exe non funziona intorno al problema dei permessi? Se l'utente deve gestirlo da solo usando SSEUtil, allora il programma di installazione non dovrebbe funzionare invocando SSEUtil? – AMissico

+0

Nei miei test questo non è sembrato essere il caso - credo che fosse solo perché l'installer non era elevato quando si invocava SSEUtil ... ma non ho avuto il tempo di approfondirlo ulteriormente. Su una nota a margine abbiamo rilevato che SSEUtil non elenca tutte le istanze utente attive correttamente su Windows 7 x64 con SqlServer e SqlServer Express installati, anche quando si passa nel parametro -s. \ SqlExpress. Quindi abbiamo ancora alcuni casi limite da risolvere :) – Bittercoder

risposta

7

Usa "SQL Server Express Utility" (SSEUtil.exe) o il comando per staccare il database utilizzato da SSEUtil.

SQL Server Express Utility, SSEUtil è uno strumento che ti permette di interagire facilmente con SQL Server, http://www.microsoft.com/downloads/details.aspx?FamilyID=fa87e828-173f-472e-a85c-27ed01cf6b02&DisplayLang=en

Inoltre, il timeout predefinito per arrestare il servizio dopo l'ultima connessione è chiusa è di un'ora. Sulla tua casella di sviluppo, potresti voler cambiare questo valore in cinque minuti (il minimo consentito).

Inoltre, è possibile che vi sia una connessione aperta attraverso le connessioni dati di Explorer Server di Visual Studio, quindi assicurarsi di disconnettersi da qualsiasi database.

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> 

Utilizzo di .NET Refector il seguente comando viene utilizzato per scollegare il 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); 
+0

Grazie, ho bisogno di richiamare questa azione da un programma di installazione WiX su macchine di molti clienti (che non avranno installato SSEUtil) ma esplorerò questa opzione come possibile . – Bittercoder

+1

SSEUtil è un'applicazione .NET. Utilizzando .NET Reflector per vedere come si stacca il database. – AMissico

+0

Suggerisco di fare il requisito del programma di installazione WiX come parte della tua domanda completa. (La tua ultima frase.) È facile perdere questo. – AMissico

2

ho utilizzato il seguente metodo di supporto per staccare file MDF collegati a SQL Server in unit test (in modo che rilascia SQ Server blocca su MDF e LDF file e il test di unità può pulire dopo se stesso) ...

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(); 
      } 
     } 
    } 
} 

Note:

  • SqlConnection.ClearAllPools() è stato molto utile nell'eliminare le connessioni "invisibili" (quando una connessione è in pool, rimarrà attiva anche se si chiude "Chiudi()", eliminando esplicitamente le connessioni del pool non ci si deve preoccupare di impostare il flag di pooling falso in tutte le stringhe di connessione).
  • "ingrediente magico" è la chiamata alla stored procedure di sistema sp_detach_db (Transact-SQL).
  • mie stringhe di connessione inclusi "AttachDBFilename", ma non ha incluso "User Instance = True", quindi questa soluzione potrebbe non applicarsi al vostro scenario
+0

Grazie per il codice - Nel mio caso ho bisogno di richiamarlo da un programma di installazione WiX (piuttosto dall'applicazione stessa, dispositivo di test ecc.) - purtroppo anche l'utente db perché l'istanza utente potrebbe non disporre di autorizzazioni sufficienti per richiamare sp_detach_db su master. Ma mi dà alcune altre opzioni da provare. – Bittercoder

+0

La seguente pagina di documentazione MSDN http://msdn.microsoft.com/en-us/library/bb264564(SQL.90).aspx afferma: "Scollegando il database dall'istanza chiamando sp_detach_db si chiuderà il file. Il metodo utilizzato da Visual Studio per garantire che il file di database venga chiuso quando l'IDE passa da un'istanza all'altra. " - Sembra che Visual Studio stesso usi sp_detach_db per chiudere le istanze utente :-). Presumo che lo strumento SSEUtil suggerito da @AMissico lo utilizzi anch'esso (ed è in pratica un modulo exe richiamabile da Wix) –

+0

Ho aggiornato la mia risposta per includere il comando effettivo utilizzato da SSEUtil. – AMissico

-3

Questo non può essere quello che stai cercando, ma il tool gratuito Unlocker è dotato di un'interfaccia a riga di comando che può essere eseguito da Wix. (Ho usato lo sblocco per un po 'e l'ho trovato stabile e molto bravo in quello che sa fare meglio, sbloccare i file.)

Unlocker può sbloccare e spostare/eliminare la maggior parte dei file.

Lo svantaggio di questo è che le app che necessitano di un blocco sul file non lo avranno più. (Ma a volte funziona ancora bene.) Si noti che questo non uccide il processo che ha il blocco. Rimuove solo il suo blocco. (Può essere che il riavvio dei servizi SQL che si sta fermando sarà sufficiente per la sua ri-lock e/o funzionare correttamente.)

si può ottenere Unlocker da qui: http://www.emptyloop.com/unlocker/

Per vedere la riga di comando opzioni di esecuzione unlocker -H Eccoli per comodità:

 
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

Supponendo che il vostro obiettivo era quello di sostituire C: \ My App \ Data \ MyApp.mdf con un file dal vostro installatore, si vorrebbe qualcosa di simile unlocker C:\My App\Data\MyApp.mdf -S -D. Questo eliminerebbe il file in modo da poterne copiare uno nuovo.

+0

Hmmmm, devi amarlo quando ottieni un voto negativo senza commento perché. – Vaccano

+1

Immagino che il down vote sia perché se l'mdf è bloccato, è per una ragione, e l'uso di unlocker può corrompere il database o qualcosa di peggio. – AMissico

1

Non riesco ancora a commentare perché non ho ancora un rappresentante abbastanza alto. Qualcuno può spostare queste informazioni nell'altra risposta in modo da non avere un duplicato?

Ho appena usato questo post per risolvere il mio problema di disinstallazione WIX. Ho usato questa linea dalla risposta di 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); 

Ha funzionato molto bene quando si utilizza WIX, solo ho dovuto aggiungere una cosa per farlo funzionare per me.

Avevo estratto lo sp_detach_db e ho riportato il db in linea. Se non lo fai, WIX lascerà i file mdf in giro dopo la disinstallazione. Una volta riavviato il db online, WIX cancellerebbe correttamente i file mdf.

Ecco la mia linea modificata.

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);