线程安全数据库连接

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全数据库连接相关的知识,希望对你有一定的参考价值。

C#在使用数据库连接是,一般采用即开即关的操作,由.net内部维护数据库连接池。但是数据库连接使用达到一定数量时候(这个好像和机器配置有关系)抛出异常。

测试代码

 1 class Program
 2     {
 3         static string constr = "Server = .;uid=test;pwd=test;";
 4         static void Main(string[] args)
 5         {
 6 
 7             Parallel.For(0, 1000, Test);
 8             Console.ReadKey();
 9 
10         }
11 
12         private static void Test(int index)
13         {
14             try
15             {
16                 SqlConnection con = new SqlConnection(constr);
17                 //只开不关模拟并发
18                 con.Open();
19                 Console.WriteLine(index);
20             }
21             catch (Exception ex)
22             {
23 
24                 Console.WriteLine(string.Format("index:{0},EX:{1}", index, ex.Message));
25             }
26         }
27     }

技术分享

一般出现这种情况我们修改连接池中最大连接数量Max Pool Size就可以解决,但这个我觉得治标不治本。

这个时候是我们最不想遇到的,个人想法就算达到了最大连接数就应该排队处理数据了 。这就需要我们在业务层面上面够着线程安全的数据库连接池。

    public class DBCmd
    {
        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        private string m_connectString;

        /// <summary>
        /// 数据库连接
        /// </summary>
        protected DbConnection m_DbConnection;

        /// <summary>
        /// 数据指令
        /// </summary>
        protected DbCommand m_DbCommand;

        /// <summary>
        /// 数据适配器
        /// </summary>
        protected DbDataAdapter m_DBAdapter;

        public string ConnectString
        {
            get { return m_connectString; }
        }

        public DBCmd(string connstr)
        {
            this.m_connectString = connstr;
        }
        protected virtual bool OpenConn()
        {
            return false;
        }

        protected virtual bool CloseConn()
        {
            return false;
        }

        /// <summary>
        /// 功 能:查询
        /// </summary>
        /// <param name="sqlCom">SQL语句</param>
        /// <param name="dsResult">查找结果</param>
        /// <returns></returns>
        public virtual int SelectCmd(string sqlCom, out DataSet dsResult)
        {
            dsResult = new DataSet();
            return 0;
        }
}
 1 public class DBCmdPool
 2     {
 3         /// <summary>
 4         /// 最小连接数
 5         /// </summary>
 6         private static int m_DBCmd_Count = 10;
 7         /// <summary>
 8         /// 数据连接栈
 9         /// </summary>
10         private static Stack<DBCmd> m_DBCmdStack = new Stack<DBCmd>();
11         //信号量来控制排队等待
12         private static Semaphore semaphore = null;
13 
14         private static object obj_lock = new object();
15         /// <summary>
16         /// 创建:周凯
17         /// 功能:数据库连接池初始化
18         /// 时间:2016-07-03
19         /// </summary>
20         /// <param name="dbCmdCount"></param>
21         public static void InitDBCmdPool(int dbCmdCount = 10)
22         {
23             lock (obj_lock)
24             {
25                 if (dbCmdCount > m_DBCmd_Count)
26                     m_DBCmd_Count = dbCmdCount;
27                 semaphore = new Semaphore(m_DBCmd_Count, dbCmdCount);
28                 m_DBCmdStack.Clear();
29                 for (int i = 0; i < m_DBCmd_Count; i++)
30                     m_DBCmdStack.Push(DBAdapter.GetDBCmd());
31             }
32         }
33 
34         public static int SelectCmd(string sqlCom, ref DataSet dsResult)
35         {
36             DBCmd cur_Cmd = GetCmd();
37             try { return cur_Cmd.SelectCmd(sqlCom, out dsResult); }
38             finally { RelCmd(cur_Cmd); }
39         }
40 
41         /// <summary>
42         /// 创建:周凯
43         /// 功能:获取数据库连接
44         /// 时间:2016-07-03
45         /// </summary>
46         /// <returns></returns>
47         private static DBCmd GetCmd()
48         {
49             if (semaphore == null)
50                 InitDBCmdPool();
51             while (true) //正常情况不用while
52             {
53                 Console.WriteLine("WaitOne");
54                 semaphore.WaitOne();
55                 DBCmd dbCmd = null;
56                 lock (obj_lock)
57                     if (m_DBCmdStack.Count > 0)
58                         dbCmd = m_DBCmdStack.Pop();
59                 Console.WriteLine((dbCmd != null).ToString());
60                 if (dbCmd != null)
61                     return dbCmd;
62                 Thread.Sleep(10);
63                 Console.WriteLine("Sleep");
64             }
65         }
66 
67         /// <summary>
68         /// 创建:周凯
69         /// 功能:回收数据库连接
70         /// 时间:2016-07-03
71         /// </summary>
72         /// <param name="dbCmd"></param>
73         private static void RelCmd(DBCmd dbCmd)
74         {
75             lock (obj_lock)
76             {
77                 m_DBCmdStack.Push(dbCmd);
78                 semaphore.Release();
79             }
80         }
81 
82  }

代码中DBCmd为sql操作父类,只需实现sql操作既可以,代码不完整只是一个思想,代码中主要的Semaphore通过信号量来控制排队。

第一次写,文笔不好,请见谅。

 

以上是关于线程安全数据库连接的主要内容,如果未能解决你的问题,请参考以下文章

线程安全数据库连接

在 Rails 上为连接、限制、选择等(不是条件)的 SQL 片段安全地转义字符串

HashMap 和 ConcurrentHashMap 的区别

JDBC 线程安全 数据库连接池

python redis连接 线程安全么

RestTemplate线程安全吗?