2010-03-02 11 views
6

Khi sử dụng tính năng Instance tài khoản SQL Server Express 2005 với một chuỗi kết nối như thế này:Làm thế nào để bạn dừng một trường hợp người dùng của Sql Server? (SQL Express sử dụng ví dụ các file cơ sở dữ liệu bị khóa, thậm chí sau khi ngừng dịch vụ Sql Express)

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

Chúng tôi thấy rằng chúng ta không thể sao chép Các tệp cơ sở dữ liệu MyApp.mdf và MyApp_Log.ldf (vì chúng bị khóa) ngay cả sau khi ngừng dịch vụ SqlExpress và phải đặt dịch vụ SqlExpress từ chế độ khởi động tự động sang thủ công, rồi khởi động lại máy, trước khi chúng ta có thể sao chép Tập tài liệu.

Đó là sự hiểu biết của tôi rằng dừng dịch vụ SqlExpress cũng sẽ dừng tất cả các phiên bản người dùng, điều này sẽ giải phóng khóa trên các tệp đó. Nhưng điều này dường như không phải là trường hợp - bất cứ ai có thể làm sáng tỏ một số cách để ngăn chặn một cá thể người dùng, sao cho các tệp cơ sở dữ liệu của nó không còn bị khóa nữa?


Cập nhật

OK, tôi dừng lại lười biếng và bắn lên Process Explorer. Khóa đã được tổ chức bởi sqlserver.exe - nhưng có hai trường hợp máy chủ sql:

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

Các tập tin được mở bởi instance sqlserver.exe với PID: 4680

Dừng "SQL Server (SQLEXPRESS) "dịch vụ, giết chết quá trình với PID: 4644, nhưng lại PID: 4680 một mình.

Thấy chủ sở hữu của quá trình còn lại là DefaultAppPool, điều tiếp theo tôi đã thử là dừng IIS (cơ sở dữ liệu này đang được sử dụng từ ứng dụng ASP.Net). Thật không may điều này đã không giết chết quá trình.

Thủ công giết chết quá trình máy chủ sql còn lại sẽ xóa xử lý tệp đang mở trên các tệp cơ sở dữ liệu, cho phép chúng được sao chép/di chuyển. Không may là tôi muốn sao chép/khôi phục các tệp đó trong một số tác vụ cài đặt trước/sau của trình cài đặt WiX - vì vậy tôi hy vọng có thể có cách để đạt được điều này bằng cách dừng dịch vụ cửa sổ, thay vào đó phải loại bỏ để giết tất cả các trường hợp của sqlserver.exe vì điều đó đặt ra một số vấn đề:

  1. Giết tất cả các trường hợp sqlserver.exe có thể có hậu quả không mong muốn cho người dùng với các phiên bản Sql Server khác trên máy của họ.
  2. Tôi không thể khởi động lại các trường hợp đó một cách dễ dàng.
  3. Giới thiệu các phức tạp bổ sung vào trình cài đặt.

Có ai có thêm bất kỳ suy nghĩ nào về cách tắt máy chủ sql được liên kết với một cá thể người dùng cụ thể không?

+0

Trả lời tất cả câu trả lời - câu trả lời hữu ích nhất là sử dụng SSEUtil.exe. Mặc dù chúng ta cần gọi điều này từ một trình cài đặt WiX nhưng chúng ta có thể thấy nó có vấn đề nhỏ nếu người dùng chạy trình cài đặt không có quyền thực thi sp_dettach_db, đây là vấn đề bất kể chúng ta sử dụng phương thức nào - vì vậy chúng ta có thể chỉ cung cấp một số bước cài đặt thủ công cho người dùng trước khi nâng cấp để họ có thể tự xử lý bằng SSEUtil.exe. – Bittercoder

+0

Tôi tò mò, không SSEUtil.exe làm việc xung quanh vấn đề cho phép? Nếu người dùng phải tự xử lý bằng SSEUtil, thì công việc cài đặt có nên gọi SSEUtil không? – AMissico

+0

Trong các thử nghiệm của tôi, điều này dường như không phải là trường hợp - tôi tin nó chỉ vì trình cài đặt không được nâng lên khi gọi SSEUtil ... nhưng tôi chưa có thời gian để điều tra thêm. Lưu ý rằng SSEUtil sẽ không liệt kê tất cả các cá thể người dùng đang hoạt động chính xác trên Windows7 x64 với cả SqlServer và SqlServer Express được cài đặt, ngay cả khi truyền tham số -s. \ SqlExpress. Vì vậy, chúng tôi vẫn còn một số trường hợp để giải quyết :) – Bittercoder

Trả lời

7

Sử dụng "SQL Server Express Utility" (SSEUtil.exe) hoặc lệnh để tách cơ sở dữ liệu được sử dụng bởi SSEUtil.

SQL Server Express Utility, SSEUtil là một công cụ cho phép bạn dễ dàng tương tác với SQL Server, http://www.microsoft.com/downloads/details.aspx?FamilyID=fa87e828-173f-472e-a85c-27ed01cf6b02&DisplayLang=en

Ngoài ra, thời gian chờ mặc định để dừng dịch vụ sau khi kết nối cuối cùng là đóng là một giờ. Trên hộp phát triển của bạn, bạn có thể muốn thay đổi điều này thành năm phút (mức tối thiểu cho phép).

Ngoài ra, bạn có thể có kết nối mở thông qua Kết nối dữ liệu máy chủ Explorer của Visual Studio, vì vậy hãy chắc chắn ngắt kết nối khỏi bất kỳ cơ sở dữ liệu nào ở đó.

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> 

Sử dụng .NET Trình lọc lệnh sau được sử dụng để tách cơ sở dữ liệu.

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

Cảm ơn, tôi cần gọi hành động này từ bên trong trình cài đặt WiX trên nhiều máy khách hàng (những người không cài đặt SSEUtil) nhưng tôi sẽ khám phá tùy chọn này . – Bittercoder

+1

SSEUtil là ứng dụng .NET. Sử dụng .NET Reflector để xem cách nó tách cơ sở dữ liệu ra sao. – AMissico

+0

Tôi khuyên bạn nên yêu cầu trình cài đặt WiX như một phần của câu hỏi đầy đủ của bạn. (Câu cuối cùng của bạn.) Rất dễ bỏ lỡ điều này. – AMissico

2

Tôi đã sử dụng phương pháp trợ giúp sau để tách các tệp MDF được gắn với SQL Server trong các bài kiểm tra đơn vị (để máy chủ SQ phát hành khóa trên các tệp MDF và LDF và thử nghiệm đơn vị có thể tự làm sạch) ...

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

Ghi chú:

  • SqlConnection.ClearAllPools() rất hữu ích trong việc loại bỏ các kết nối "tàng hình" (khi kết nối được gộp lại, nó sẽ vẫn hoạt động ngay cả khi bạn 'Đóng'), bằng cách xóa kết nối hồ bơi rõ ràng bạn không phải lo lắng về việc thiết lập cờ tổng hợp thành sai trong tất cả các chuỗi kết nối).
  • "thành phần ma thuật" là gọi đến quy trình được lưu trữ hệ thống sp_detach_db (Transact-SQL).
  • chuỗi kết nối của tôi bao gồm "AttachDBFilename" nhưng không bao gồm "User Instance = True", vì vậy giải pháp này có thể không áp dụng đối với kịch bản của bạn
+0

Cảm ơn mã - Trong trường hợp của tôi, tôi cần gọi điều này từ trình cài đặt WiX (thay vào đó là bản thân ứng dụng, lịch thi đấu, v.v.) - cũng không may là người dùng db cho trường hợp người dùng có thể không có đủ quyền để gọi sp_detach_db trên master. Nhưng nó cung cấp cho tôi một số tùy chọn khác để thử. – Bittercoder

+0

Trang tài liệu MSDN sau http://msdn.microsoft.com/en-us/library/bb264564(SQL.90).aspx tuyên bố: "Việc tách cơ sở dữ liệu khỏi cá thể bằng cách gọi sp_detach_db sẽ đóng tệp. Đây là phương pháp Visual Studio sử dụng để đảm bảo rằng tệp cơ sở dữ liệu được đóng khi IDE chuyển đổi giữa các cá thể người dùng. " - Có vẻ như Visual Studio sử dụng sp_detach_db để đóng các cá thể người dùng :-). Tôi giả sử công cụ SSEUtil được đề xuất bởi @AMissico cũng sử dụng nó (và nó có dạng exe tiện dụng có thể invokable từ Wix) –

+0

Tôi đã cập nhật câu trả lời của mình để bao gồm lệnh thực tế được sử dụng bởi SSEUtil. – AMissico

-3

Đây có thể không phải là những gì bạn đang tìm kiếm, nhưng Công cụ miễn phí có giao diện dòng lệnh có thể chạy từ WIX. (Tôi đã sử dụng trình mở khoá trong một thời gian và thấy nó ổn định và rất tốt ở những gì nó hoạt động tốt nhất, mở khóa các tệp.)

Trình mở khóa có thể mở khóa và di chuyển/xóa hầu hết mọi tệp.

Nhược điểm của việc này là các ứng dụng cần khóa trên tệp sẽ không còn có tệp đó nữa. (Nhưng đôi khi vẫn làm việc tốt.) Lưu ý rằng điều này không giết chết quá trình có khóa. Nó chỉ loại bỏ khóa của nó. (Có thể là khởi động lại dịch vụ sql mà bạn đang dừng sẽ là đủ cho nó để lại khóa và/hoặc hoạt động chính xác.)

Bạn có thể nhận Unlocker từ đây: http://www.emptyloop.com/unlocker/

Để xem dòng lệnh tùy chọn chạy unlocker -H ở đây họ cho tiện theo dõi:

 
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

Giả sử mục tiêu của bạn là để thay thế C: \ My App \ Data \ MyApp.mdf với một tập tin từ trình cài đặt của bạn, bạn sẽ muốn một cái gì đó giống như unlocker C:\My App\Data\MyApp.mdf -S -D. Thao tác này sẽ xóa tệp để bạn có thể sao chép tệp mới.

+0

Hmmmm, gotta thích nó khi bạn nhận được một cuộc bỏ phiếu xuống không có bình luận tại sao. – Vaccano

+1

Tôi sẽ tưởng tượng cuộc bỏ phiếu xuống là bởi vì nếu mdf bị khóa, đó là vì một lý do và việc sử dụng trình mở khóa có thể làm hỏng cơ sở dữ liệu hoặc điều gì đó tồi tệ nhất. – AMissico

1

Tôi chưa thể nhận xét vì tôi chưa có đại diện đủ cao. Ai đó có thể di chuyển thông tin này vào câu trả lời khác để chúng tôi không bị lừa đảo?

Tôi vừa sử dụng bài đăng này để giải quyết vấn đề gỡ cài đặt WIX của mình. Tôi đã sử dụng dòng này từ câu trả lời của 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); 

Làm việc khá tốt khi sử dụng WIX, chỉ có tôi phải thêm một thứ để làm cho nó hoạt động cho tôi.

Tôi đã lấy ra sp_detach_db và sau đó đưa db trở lại trực tuyến. Nếu không, WIX sẽ để lại các tệp mdf xung quanh sau khi gỡ cài đặt. Một khi tôi đưa db trở lại trực tuyến WIX sẽ xóa các tệp mdf đúng cách.

Đây là dòng được sửa đổi của tôi.

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