今晚看到上了评论头条的LoveJenny写的为什么要关闭数据库连接,可以不关闭吗?,文章写得简单易懂非常不错,而且代码贴的很到位,下面的讨论也很激烈(老赵都跑过去留言两次了,我恨)。又查看了两遍原文中的代码,我同意评论中有几位的看法,真正造成多线程并行操作数据库时的连接问题可能是由于对SqlConnection的不当使用。为什么呢?再来看一下LoveJenny兄弟贴出的一段重要源码:

           string sqlConnString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=""E:\DB\NORTHWND.mdf"";Integrated Security=True;Connect Timeout=30;User Instance=True";SqlConnection conn = new SqlConnection(sqlConnString);conn.Open();Parallel.For(1, Int32.MaxValue, (id) =>{ExecuteCommand(conn, id);});

其中,ExecuteCommand的具体实现如下:

        private static object syncObj = new object();private static void ExecuteCommand(SqlConnection conn, int id){lock (syncObj){if (conn.State != ConnectionState.Open){conn.Open();}Console.WriteLine("正在执行." + id);Thread.Sleep(100);SqlCommand cmd = new SqlCommand(string.Format("Insert into Nums values('{0}') ", id), conn);cmd.ExecuteNonQuery();}}

代码很简洁,但是很多人包括我自己忍不住都会有几个重大疑问:

1、怎么并行操作n多次数据库只共用一个连接对象呢?

2、并行处理的地方加了锁,每次进行数据库操作都要Lock一下(我感觉这根本没有发挥多线程并行处理的优势,个人认为还不如单线程执行的快呢),这个真的有这个必要吗?

3、同一个数据库连接字符串,使用数据库连接对象SqlConnection怎么还要传参呢,显式Open和Close不是更好吗?通常不都是using一下完事吗?

经过简单思考之后,在本地机器上改进了一下实现代码进行测试,如下:

          Parallel.For(1, Int32.MaxValue, (id) =>{ExecuteCommand(id);});

ExecuteCommand方法不再接受SqlConnection对象作为参数,去掉Lock,数据库操作看上去就像是操作一次数据库,打开一次数据库连接,保证线程安全:

        private static void ExecuteCommand(int id){using (SqlConnection conn = new SqlConnection(sqlConnString)){conn.Open();Console.WriteLine("正在执行." + id);Thread.Sleep(100);SqlCommand cmd = new SqlCommand(string.Format("Insert into Nums values('{0}') ", id), conn);cmd.ExecuteNonQuery();}}

当然ExecuteCommand也可以通过显式Open和Close处理:

        private static void ExecuteCommand(int id){SqlConnection conn = new SqlConnection(sqlConnString);conn.Open();Console.WriteLine("正在执行." + id);Thread.Sleep(100);SqlCommand cmd = new SqlCommand(string.Format("Insert into Nums values('{0}') ", id), conn);cmd.ExecuteNonQuery();conn.Close();}

根据我的本地机器测试,上面改进后的两种写法数据库连接对象使用正常,线程安全,而且在性能上比加锁操作数据库提高显著,有兴趣的你也不妨一试。

但是,本文的目的不在说代码如何改进才能线程安全提升性能,而是要说明一个非常简单的问题,如何正确合理地使用数据库连接对象SqlConnection?

那么到底如何正确合理地使用数据库连接对象SqlConnection?

最经典的说法莫过于就是using一下即可,这种说法其实是非常正确的,MSDN的使用方法通常也都是using一下,很普遍很潇洒:

SqlConnection      private static void OpenSqlConnection(){string connectionString = GetConnectionString();using (SqlConnection connection = new SqlConnection(connectionString)){connection.Open();Console.WriteLine("ServerVersion: {0}", connection.ServerVersion);Console.WriteLine("State: {0}", connection.State);}}static private string GetConnectionString(){// To avoid storing the connection string in your code, // you can retrieve it from a configuration file, using the // System.Configuration.ConfigurationSettings.AppSettings property return "Data Source=(local);Initial Catalog=AdventureWorks;"+ "Integrated Security=SSPI;";}

其实我们都知道SqlConnection对象一定继承自IDispose接口,然后才可以using。using使用的对象最后都会Dispose处理掉,难道数据库连接对象的Close方法和Dispose是等价的?

这里明确告诉您,通过显式Close和using后Dispose是不一样的。到这里是不是很想知道Dispose和Close的区别?

MSDN对Close方法的解释是这样的:

关闭与数据库的连接,这是关闭任何打开连接的首选方法。 如果 SqlConnection超出范围,则不会将其关闭。因此,必须通过调用 Close 或 Dispose 显式关闭该连接。Close 和 Dispose 在功能上等效。如果连接池值 Pooling 设置为 true 或 yes,则基础连接将返回到连接池。另一方面,如果 Pooling 设置为 false 或 no,则会关闭到服务器的基础连接。

我们可以这样理解:通过调用Close方法关闭的SqlConnection对象,最后是要放回到连接池中的,也就是说这个对象还可以继续使用,只是这个对象现在的连接状态是关闭的,等到下次向池中申请连接对象,这个对象就可以激活复用而不用去new一个新的对象。

而通过调用Dispose()方法,则该对象很可能调用了GC.SuppressFinalize(this)(某些特殊的类可能并没有调用该方法),这样GC就会优先对这些对象进行回收而可能造成该对象无法使用。这里我们只要理解,在SqlConnection对象上调用Dispose方法,则这个连接就不能在连接池中继续使用了。

最后说明一下,ado.net使用了连接池技术用来复用连接,减少系统反复打开关闭连接的开销来提升性能,所以我上面说通过using“数据库操作看上去就像是操作一次数据库,打开一次数据库连接,保证线程安全”其实也是不对的。下面摘录一段MSDN的说法解惑:

连接池使新连接必须打开的次数得以减少。池进程保持物理连接的所有权。通过为每个给定的连接配置保留一组活动连接来管理连接。每当用户在连接上调用 Open 时,池进程就会查找池中可用的连接。如果某个池连接可用,会将该连接返回给调用者,而不是打开新连接。应用程序在该连接上调用 Close 时,池进程会将连接返回到活动连接池集中,而不是关闭连接。连接返回到池中之后,即可在下一个 Open 调用中重复使用。

只有配置相同的连接可以建立池连接。ADO.NET 同时保留多个池,每种配置各一个。在使用集成的安全性时,连接按照连接字符串以及 Windows 标识分到多个池中。还根据连接是否已在事务中登记来建立池连接。

池连接可以显著提高应用程序的性能和可缩放性。默认情况下,在 ADO.NET 中启用连接池。除非显式禁用,否则,在应用程序中打开和关闭连接时,池进程会对连接进行优化。还可以提供几个连接字符串修饰符来控制连接池的行为。

我们可以显式对连接池进行一些操作,但是通常不建议这么做。对连接池您还有什么疑惑吗?欢迎讨论。

参考:

http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnection(VS.80).aspx

http://msdn.microsoft.com/zh-cn/library/8xx3tyca(VS.90).aspx

正确使用SqlConnection对象,兼谈数据库连接池相关推荐

  1. 浅谈数据库连接池原理及优势

    https://blog.csdn.net/C99965/article/details/107488372 连接池的工作原理主要由三部分组成,分别为 第一.连接池的建立. 一般在系统初始化时,连接池 ...

  2. 数据库连接池_DataSource_数据源(简单介绍C3P0和Druid)

    文章目录 概念 好处 实现 C3P0 基本使用 配置文件 druid 下载 jar 包 配置文件 演示代码 定义工具类 示例代码 概念 数据库连接池其实就是一个容器,而这个容器其实就是一个集合,这个集 ...

  3. 基于MysqlConnector/C++的数据库连接池的实现

    From: http://blog.csdn.net/educast/article/details/14164097 1.连接池的介绍: 1.1应用背景: 一般的应用程序都会访问到数据库,在程序访问 ...

  4. mysql连接池_数据库技术:数据库连接池,Commons DbUtils,批处理,元数据

    Database Connection Pool Introduction to Database Connection Pool 实际开发中"获得连接"或"释放资源&q ...

  5. MyBatis 简介、 环境搭建、数据库连接池、查询方式

    七.MyBatis 简介 Mybatis 开源免费框架.原名叫 iBatis,2010 在 google code,2013 年迁移到 github 作用: 数据访问层框架. 2.1 底层是对 JDB ...

  6. c3p0,DBCP,Druid(德鲁伊)数据库连接池

    c3p0,DBCP,Druid(德鲁伊)数据库连接池 每博一文案 佛说:前世 500 次的回眸,才换来今生的一次擦肩而过. 人与人之间的缘分,真的无需强求,并不是所有的感情都能天长地久,正如<越 ...

  7. e2ee连接mysql数据库_E2EE应用服务器套件 - 文档 - [高级功能] 使用数据库连接池 - E2EE易语言网站敏捷开发框架...

    使用数据库连接池 E2EE内置ADO作为通用数据库解决方案. 使用数据库连接池和操作数据库主要有三个对象: ADODB数据库连接池 ADODB数据库连接 ADODB数据库分页 1. 创建连接池 创建数 ...

  8. 2021-3-28 JDBC入门包含数据库连接池

    里面的数据库连接池所需要的jar包可以在这里面下载: https://blog.csdn.net/m0_49647974/article/details/115287069 文章目录 一.概念:Jav ...

  9. JDBC工具类,基于C3P0的数据库连接池,提供获取连接池、获取连接对象、释放资源和封装事务操作的方法...

    /**  *  * JDBC工具类,基于C3P0数据库连接池的实现  *  * @author 周瑜  * @2018年5月7日 下午2:13:20  */ public final class JD ...

  10. 浅谈各种数据库连接池

      1.各种数据库连接池    开源的免费连接池: DBCP  C3P0  Proxool  Druid  Jakarta  DDConnectionBroker  BoneCP XAPool  Pr ...

最新文章

  1. [Leetcode] Simplify Path
  2. C++编程进阶8(最好不要实现类型转换运算符、单形参的构造函数与类型转换、临时对象与RVO)
  3. Bootstrap组件_路径导航,标签,徽章
  4. 隐藏GridControl的“Drag a column header here to group by that column”
  5. float32精度_PyTorch 1.6来了:新增自动混合精度训练、Windows版开发维护权移交微软...
  6. 计算机电力英语翻译,电力专业英语阅读与翻译..doc
  7. 【抽象代数】代数系统、群与商群
  8. centos7 mysql创建表_centos7下创建数据库和用户
  9. 有趣的应用 | 使用RNN预测股票价格系列一
  10. 多线程的那点儿事(基础篇)
  11. cacti mysql-bin_Cacti环境搭建(LNMP环境)
  12. leetCode----day01---- 从排序数组中删除重复项
  13. ArcGIS Server .net Web ADF 体系结构
  14. Linux安装log4cpp
  15. CSS 图像居中对齐
  16. 【测试人生】安卓FPS测试详解
  17. 【转】火影10大秘密最终之解(杜撰)
  18. ORACLE通过dblink同步SDO_ORDINATE_ARRAY_STR的数据
  19. html 占两行,css – 将html页面分成两行50%的高度
  20. 数据结构与算法学习笔记4:递归+分治法

热门文章

  1. 智能视频监控中的多目标跟踪分析
  2. ps提示“脚本错误-50出现一般Photoshop错误的解决方法
  3. PPDuck3 for Mac(pp鸭图片批量压缩工具)最新官方版免下载
  4. 如何显示或隐藏Mac电脑右上角的声音图标
  5. OC 中property属性详解(assign , retain , copy , strong,weak,readonly , readwrite , atomic , nonatomic)
  6. EasyRecovery如何恢复游戏——英雄联盟
  7. quartz配置参数说明
  8. 11月19日 数据库连接 PDO
  9. 课下参考五 linux的ssh服务实现多用户登录linux系统--windows客户端篇
  10. Max Points on a Line@LeetCode