以前曾見過有人這樣寫代碼:
?
public class Service1 : IService1
{
private SqlConnection conn = new SqlConnection();
public void Method1()
{
//do something with conn;
}
public void Method2()
{
//do something with conn;
}
public void Method3()
{
//do something with conn;
}
public void Method4()
{
//do something with conn;
}
}
?
在服務類中,新建一個全局的conn對象,然后使用conn對象來操作數據庫。
當然,還有一些不同的版本,比如:
private SqlConnection conn = new SqlConnection();
private static SqlConnection sconn = new SqlConnection();
private SqlConnection Conn
{
get { return new SqlConnection(); }
}
?
如果有人問你哪種方式比較好,你會怎么回答?
?
首先驗證下在多線程環境下使用一個Connection的方式:
創建控制臺程序:
Main代碼如下:
public static void Main()
{
string connectionString = @"Data Source=.\SQLEXPRESS;
AttachDbFilename=""E:\DB\NORTHWND.mdf"";
Integrated Security=True;
Connect Timeout=30;User Instance=True";
string connectionStringNoPooling = connectionString + " ;Pooling='false' ";
SqlConnection conn = new SqlConnection(connectionString);
new Thread(() => { ExecuteCommand(conn); }) { Name = "t1" }.Start();
new Thread(() => { ExecuteCommand(conn); }) { Name = "t2" }.Start();
}
public static void ExecuteCommand(SqlConnection conn)
{
Console.WriteLine("Thread:{0},{1}", Thread.CurrentThread.Name, DateTime.Now);
conn.Open();
SqlCommand command = new SqlCommand("select * from customers", conn);
command.ExecuteNonQuery();
command.Dispose();
Thread.Sleep(5000); //模擬耗時的查詢
conn.Close();
Console.WriteLine("Thread:{0} 執行完畢,{1}", Thread.CurrentThread.Name, DateTime.Now);
}
?
代碼很簡單,模擬兩個線程同時執行ExecuteCommand.方法。結果如下:
?
可以知道在多線程環境下使用一個Connection來執行Sql語句是不安全的,
修改Main函數如下:將一個Connection,改為多個Connection
public static void Main()
{
string connectionString = @"Data Source=.\SQLEXPRESS;
AttachDbFilename=""E:\DB\NORTHWND.mdf"";
Integrated Security=True;
Connect Timeout=30;User Instance=True";
string connectionStringNoPooling = connectionString + " ;Pooling='false' ";
//SqlConnection conn = new SqlConnection(connectionString);
//new Thread(() => { ExecuteCommand(conn); }) { Name = "t1" }.Start();
//new Thread(() => { ExecuteCommand(conn); }) { Name = "t2" }.Start();
SqlConnection conn1 = new SqlConnection(connectionString);
SqlConnection conn2 = new SqlConnection(connectionString);
new Thread(() => { ExecuteCommand(conn1); }) { Name = "t1" }.Start();
new Thread(() => { ExecuteCommand(conn2); }) { Name = "t2" }.Start();
Console.ReadLine();
}
?
運行結果如下:
既然多個Connection比一個Connection要好,
為什么還是有人使用上面的那種寫法來創建Connection呢?
我認為他們可能會認為創建多個Connection比較耗時,而且多個Connection會占用內存,影響性能等等。。
在這一點上可以使用測試數據來說明:
測試數據來自:Connection-Pooling vs. Reusing one connection
?
Run # | NCP | CP | OC |
1 | 4073 | 374 | 237 |
2 | 4032 | 341 | 298 |
3 | 3985 | 353 | 242 |
4 | 4085 | 348 | 269 |
5 | 3964 | 369 | 256 |
6 | 4203 | 330 | 207 |
7 | 4055 | 341 | 359 |
8 | 4071 | 357 | 286 |
9 | 3968 | 363 | 356 |
10 | 4023 | 349 | 359 |
AVG | 4046 | 353 | 287 |
?
Run #:1代表1000次查詢,2代表2000次查詢
NCP :Not Connection Pool ,未啟用數據庫連接池
CP :Connection Pool,啟用數據庫連接池
OC :One Connection,一個連接對象
從圖表可以發現啟用了連接池的方式并不比重用一個連接慢多少。
但是從穩定性,程序的健壯性來說,CP的方式明顯的好于OC。
?
所以下次實現服務,或者是查詢的時候完全可以使用
public SqlConnection Connection
{
get
{
return new SqlConnection(@"...");
}
}
而不要
private SqlConnection conn = new SqlConnection(connectionString);