A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

以前曾见过有人这样写代码:

  1. public class Service1 : IService1
  2.     {
  3.         private SqlConnection conn = new SqlConnection();
  4.         public void Method1()
  5.         {
  6.             //do something with conn;
  7.         }
  8.         public void Method2()
  9.         {
  10.             //do something with conn;
  11.         }
  12.         public void Method3()
  13.         {
  14.             //do something with conn;
  15.         }
  16.         public void Method4()
  17.         {
  18.             //do something with conn;
  19.         }
  20.     }
复制代码
在服务类中,新建一个全局的conn对象,然后使用conn对象来操作数据库。
当然,还有一些不同的版本,比如:

  1. private SqlConnection conn = new SqlConnection();
  2. private static SqlConnection sconn = new SqlConnection();
  3. private SqlConnection Conn
  4. {
  5.     get { return new SqlConnection(); }
  6. }
复制代码
如果有人问你哪种方式比较好,你会怎么回答?

首先验证下在多线程环境下使用一个Connection的方式:
创建控制台程序:
Main代码如下:

  1. public static void Main()
  2. {
  3.     string connectionString = @"Data Source=.\SQLEXPRESS;
  4.                                 AttachDbFilename=""E:\DB\NORTHWND.mdf"";
  5.                                 Integrated Security=True;
  6.                                 Connect Timeout=30;User Instance=True";
  7.     string connectionStringNoPooling = connectionString + " ;Pooling='false' ";
  8.     SqlConnection conn = new SqlConnection(connectionString);
  9.     new Thread(() => { ExecuteCommand(conn); }) { Name = "t1" }.Start();
  10.     new Thread(() => { ExecuteCommand(conn); }) { Name = "t2" }.Start();
  11. }
  12. public static void ExecuteCommand(SqlConnection conn)
  13. {
  14.     Console.WriteLine("Thread:{0},{1}", Thread.CurrentThread.Name, DateTime.Now);

  15.     conn.Open();

  16.     SqlCommand command = new SqlCommand("select * from customers", conn);
  17.     command.ExecuteNonQuery();
  18.     command.Dispose();
  19.     Thread.Sleep(5000); //模拟耗时的查询
  20.     conn.Close();
  21.     Console.WriteLine("Thread:{0} 执行完毕,{1}", Thread.CurrentThread.Name, DateTime.Now);
  22. }
复制代码
代码很简单,模拟两个线程同时执行ExecuteCommand.方法。结果如下:




可以知道在多线程环境下使用一个Connection来执行Sql语句是不安全的,

修改Main函数如下:将一个Connection,改为多个Connection

  1. public static void Main()
  2. {
  3.     string connectionString = @"Data Source=.\SQLEXPRESS;
  4.                                 AttachDbFilename=""E:\DB\NORTHWND.mdf"";
  5.                                 Integrated Security=True;
  6.                                 Connect Timeout=30;User Instance=True";
  7.     string connectionStringNoPooling = connectionString + " ;Pooling='false' ";
  8.     //SqlConnection conn = new SqlConnection(connectionString);
  9.     //new Thread(() => { ExecuteCommand(conn); }) { Name = "t1" }.Start();
  10.     //new Thread(() => { ExecuteCommand(conn); }) { Name = "t2" }.Start();
  11.     SqlConnection conn1 = new SqlConnection(connectionString);
  12.     SqlConnection conn2 = new SqlConnection(connectionString);
  13.     new Thread(() => { ExecuteCommand(conn1); }) { Name = "t1" }.Start();
  14.     new Thread(() => { ExecuteCommand(conn2); }) { Name = "t2" }.Start();
  15.     Console.ReadLine();
  16. }
复制代码
运行结果如下:



既然多个Connection比一个Connection要好,

为什么还是有人使用上面的那种写法来创建Connection呢?

我认为他们可能会认为创建多个Connection比较耗时,而且多个Connection会占用内存,影响性能等等。。

在这一点上可以使用测试数据来说明:

测试数据来自:Connection-Pooling vs. Reusing one connection


Run #:1代表1000次查询,2代表2000次查询

NCP :Not Connection Pool ,未启用数据库连接池

CP :Connection Pool,启用数据库连接池

OC :One Connection,一个连接对象

从图表可以发现启用了连接池的方式并不比重用一个连接慢多少。

但是从稳定性,程序的健壮性来说,CP的方式明显的好于OC。

所以下次实现服务,或者是查询的时候完全可以使用

  1. public SqlConnection Connection
  2. {
  3.     get
  4.     {
  5.         return new SqlConnection(@"...");
  6.     }
  7. }
复制代码
而不要
private SqlConnection conn = new SqlConnection(connectionString);



评分

参与人数 1技术分 +1 收起 理由
haxyek + 1

查看全部评分

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马