线程安全数据库连接
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 片段安全地转义字符串