2009-07-17 27 views
34

Tôi hiểu rằng nếu tôi khởi tạo một đối tượng SqlConnection, tôi thực sự lấy một kết nối từ một nhóm kết nối. Khi tôi gọi Open(), nó sẽ mở kết nối. Nếu tôi gọi phương thức Close() hoặc Dispose() trên đối tượng SqlConnection đó, nó sẽ được trả về pool kết nối.Làm thế nào để buộc một SqlConnection để đóng cửa vật lý, trong khi sử dụng kết nối tổng hợp?

Tuy nhiên, điều đó không thực sự cho tôi biết nếu nó thực sự bị đóng hoặc nếu tôi vẫn có kết nối hoạt động với cơ sở dữ liệu.

Làm cách nào để buộc SqlConnection đóng ở cấp mạng, hoặc ít nhất là phải biết khi nào nó đóng?

Ví dụ:

using(SqlConnection conn = new SqlConnection(DBConnString)) { 

    conn.Open(); 
    SqlCommand cmd = conn.CreateCommand(); 
    ... 
    cmd.ExecuteReader(CommandBehavior.CloseConnection); 
    ... 
} 
  • Đầu tiên chạy: 300 ms
  • Second chạy: 100 ms
  • thứ ba chạy: 100 ms
  • Sau khi chờ đợi một thời gian dài (30 phút) : 300 ms

Nếu kết nối là TRULY kết thúc, lần chạy thứ hai và thứ ba cũng phải là 300 ms. Nhưng tôi biết rằng kết nối không thực sự bị đóng cho những lần chạy đó (tôi đã kiểm tra màn hình hoạt động của SQL Server). Nó không mất thêm 200ms để thực hiện xác thực/etc.

Làm cách nào để buộc kết nối thực sự đóng?

Ý tưởng

  • Liệu CommandBehavior.CloseConnection làm việc? (dường như không?)
  • Cài đặt "Kích thước hồ bơi tối đa = 0" trong chuỗi kết nối có hoạt động không? (đây sẽ là giải pháp pyrrhic)
  • Dispose() có hoạt động không?

Tài liệu tham khảo

Trả lời

48
+2

+1 cho người trả lời đầu tiên để đọc câu hỏi đúng cách. – Joe

+1

Tôi đang làm điều này, nhưng kết nối SQL của tôi vẫn hiển thị trong sp_who2 và khóa phiên giữ SQL của tôi vẫn bị khóa (tôi dự định chúng sẽ chết với kết nối). Tôi thậm chí còn đặt ['connStrBuilder.Polling = false'] (https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.close (v = vs.110) .aspx). –

0

CommandBehavior.CloseConnection thường không được khuyến khích vì thực tế này rất - Bạn không thể chắc chắn rằng kết nối sẽ được đóng lại. (Tôi sẽ cố gắng tìm một số bằng chứng cụ thể về điều này, tôi đang nói điều này từ việc thu hồi mờ nhạt).

Dispose() là cách trả trước vì nó hoàn toàn gọi Close().

Cấu trúc using được chứng minh bằng @Alex chỉ là một cách khác (lập trình thân thiện) bằng cách viết cấu trúc try-finally với việc thêm vào Ẩn đối tượng.

Edit: (sau khi chỉnh sửa câu hỏi)

mối quan tâm của bạn qua kết nối thực bế mạc dường như không chính đáng đối với tôi. Kết nối sẽ chỉ đơn giản là trở lại hồ bơi để nó có thể được tái sử dụng dễ dàng mà không cần phải đi qua tất cả các khởi tạo. Điều này không có nghĩa là kết nối vẫn được kết nối tích cực với DB.

+2

Kết nối trong hồ bơi ** không ** có nghĩa là nó vẫn được kết nối hoạt động với DB. Ví dụ bạn có thể đóng một đối tượng Connection, và bạn vẫn sẽ có một khóa cơ sở dữ liệu shard do kết nối vẫn đang ở trong pool (http: // stackoverflow.com/questions/520716/ado-net-sqlserver-cách-để-ngăn-đóng-kết nối-từ-giữ-s-db-lock) –

9

Nếu bạn không muốn sử dụng nhóm kết nối, bạn phải chỉ định nó trong thuộc tính SqlConnection.ConnectionString của mình. Ví dụ

"Data Source=MSSQL1;Database=AdventureWorks;Integrated Security=true;Pooling=false;" 

Vứt bỏ hoặc đóng đối tượng SqlConnection là chỉ cần đi để đóng kết nối và gửi lại cho các hồ bơi kết nối.

3

Nói chung, bạn muốn nhóm kết nối thực hiện công việc của mình - bạn không muốn kết nối thực sự đóng.

Tại sao bạn muốn kết nối không quay lại hồ bơi?

+2

Kết nối trong hồ bơi có thể giữ khóa. –

+1

Tôi cũng không chắc chắn loại khóa bạn đang đề cập đến - kết nối được xử lý có kết nối cơ bản được trả lại cho nhóm kết nối không được tham gia vào bất kỳ giao dịch nào hoặc giữ bất kỳ khóa nào liên quan đến mã tiêu thụ. Tất nhiên nó vẫn đang sử dụng một cổng mạng và một vài tài nguyên khác - nhưng chi phí mua lại rất lớn của các tài nguyên này là * tại sao * bạn * không * những gì để giải phóng chúng. Trừ khi bạn đang cố gắng để xóa/khôi phục cơ sở dữ liệu cơ bản hoặc một cái gì đó tương tự triệt để, các ổ khóa không phải là vấn đề. –

+1

Kết nối trong hồ bơi có thể ngăn truy cập độc quyền vào cơ sở dữ liệu. – kevmar

23

Câu trả lời của Moe Sisko (Gọi SqlConnection.ClearPool) là chính xác.

Đôi khi bạn cần kết nối để thực sự gần hơn là quay lại hồ bơi. Ví dụ, tôi có một bài kiểm tra đơn vị tạo ra một cơ sở dữ liệu đầu, xây dựng lược đồ, kiểm tra một số công cụ, sau đó giảm cơ sở dữ liệu cào nếu tất cả các bài kiểm tra đều vượt qua.

Khi kết nối tổng hợp đang hoạt động, lệnh thả cơ sở dữ liệu không thành công do vẫn còn các kết nối đang hoạt động. Từ quan điểm của lập trình viên tất cả các SQLConnections được đóng lại, nhưng như hồ bơi vẫn giữ một mở, SQL Server sẽ không cho phép thả.

Tài liệu hay nhất về cách xử lý tổng hợp kết nối là this page on SQL Server Connection Pooling trên MSDN. Người ta không muốn tắt kết nối tổng hợp hoàn toàn bởi vì nó cải thiện hiệu suất với việc mở và đóng lặp lại, nhưng đôi khi bạn cần gọi một "lực đóng" trên một SQLConnection để nó sẽ loại bỏ cơ sở dữ liệu.

Việc này được thực hiện với ClearPool. Nếu bạn gọi SqlConnection.ClearPool(connection) trước khi đóng/xử lý, khi bạn đóng/hủy nó sẽ thực sự biến mất.

+0

Trường hợp sử dụng bạn mô tả gần như chính xác những gì tôi đang làm - kiểm tra hiệu suất của một số mẫu truy cập db, sử dụng thủ tục "lạnh"/cache dữ liệu và tất nhiên, các kết nối. –

+0

Liên kết bạn cung cấp đã được thêm vào văn bản câu hỏi. Cảm ơn. –

+0

Kịch bản tương tự cho tôi :-) –

-2

Câu trả lời của Robert là SqlConnection.ClearPool(TheSqlConn) đã làm chính xác những gì tôi muốn. Thật tuyệt khi biết hồ bơi CÓ THỂ được tương tác khi cần thiết.

Trường hợp sử dụng của tôi là: Chúng tôi đã hủy kết nối và để nó quay trở lại hồ bơi, cách chúng tôi phát hiện thấy nó bị hủy hoại và làm mới nó, vì vậy người dùng tiếp theo sẽ không gặp sự cố.

Giải pháp là: Phát hiện rằng chúng tôi vừa hủy hoại kết nối và xóa hoàn toàn khỏi hồ bơi, cho phép hồ bơi lấp đầy các kết nối mới.

Một thập kỷ viết SqlClient.SqlConnection và tôi thậm chí không bao giờ nghĩ đến việc tương tác với hồ bơi cho đến hôm nay.

Các vấn đề liên quan