目录
1.起因:
在做一个小系统的时候,我想数据量交互不大,就都用一个链接执行算了,还能节省点资源,但是实际情况遇到了如下问题,在使用的过程中,有些数据操作会被转移到其他线程,这样;我这个简单的想法遇到了问题,因为一个现场在使用这个链接的时候,其他线程也会同步插入执行数据操作,这样一个链接就会面临共用的冲突,怎么办呢,有如下三种方案:
1.1.数据两次一次一联,一用,一释放。
1.2.强制是数据库的执行放到一个现场,那么得把所有的执行参数放到队列中,有数据支持的线程按照队列的顺序执行。也可以在使用的时候把链接索起来。这样强制的使数据的处理串行。
1.3.做一个内部的链接对象使用池,池中的对象可供服用,解决重复链接的问题,提供多个对象解决现场使用冲突的问题。
我选择了方案三,做了如下实验,记录如下
2.实验
2.1 确认数据链接状态,使用完的数据链接是什么状态呢?
2.1.1 目的:我想根据链接的状态判断链接是在使用中,还是可以给别人使用;就是在可以使用的情况下,我就用该链接执行,否则使用或者创建其他的链接。
代码。
using System; using System.Data; namespace 数据库链接状态确认 { /// <summary> /// 确认数据库通常执行完成是什么状态 /// </summary> public class Test1:Singleton<Test1> { public void main() { test1(); } private void test1() { DBmsqlSub dBmsqlSub = new DBmsqlSub(); string sql = "insert into tb1(v1) values(2)"; dBmsqlSub.ExecuteNonQuery(sql); ConnectionState connectionState = dBmsqlSub.getState(); Console.WriteLine(connectionState); dBmsqlSub.Close(); } } }
结果,整理使用后的链接状态是open,那是不是open的时候就可以供别人使用了呢,要是在执行的时候也是open状态,那我就没有判定已经了。
数据库链接状态确认 id0 index:1 isuser:False setuser:False Open
2.2 数据库在执行的时候,是不是有一个执行中的状态呢?
代码
using System; using System.Threading.Tasks; namespace 数据库链接状态确认 { /// <summary> /// 目的:确认执行中的数据状态 /// </summary> class Test2:Singleton<Test2> { public void main() { DBmsqlSub dBmsqlSub = new DBmsqlSub(); Task.Factory.StartNew(test2Exe, (Object)dBmsqlSub); Task.Factory.StartNew(test2Exe, (Object)dBmsqlSub); Task.Factory.StartNew(test2State, dBmsqlSub); } private void test2Exe(object dBmsqlSub) { int index = 1; while (true) { index++; string sql = "insert into tb1(v1) values(" + index + ")"; ((DBmsqlSub)dBmsqlSub).ExecuteNonQuery(sql); Task.Delay(200); } } private void test2State(object dBmsqlSub) { while (true) { Console.WriteLine(((DBmsqlSub)dBmsqlSub).getState()); } } } }
行结果执:即使执行中,对象的链接状态依然是open,那么用链接状态作为链接是否可用的计划泡汤了,那就只能用自添加的对象来控制链接是否可用了。
Open
Open
Open
Open
id0
Open
Open
Open
Open
Open
Open
2.3 测试3:添加对象的状态,控制链接是否可用
2.3.1 代码
using MySqlConnector; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 数据库链接状态确认 { class Test3:Singleton<Test3> { public void main() { test1(); //test1(); } private void test1() { Task.Factory.StartNew(test2Exe); Task.Factory.StartNew(test2Exe); Task.Factory.StartNew(test2Exe); } private void test2Exe() { int index = 1; while (true) { index++; string sql = "insert into tb1(v1) values(" + index + ")"; DBmsql.getMy().ExecuteNonQuery(sql); } } private object MySqlDataReader(DBmsqlSub dBmsqlSub) { throw new NotImplementedException(); } private void test2State(object dBmsqlSub) { while (true) { Console.WriteLine(((DBmsqlSub)dBmsqlSub).getState()); } } } }
2.3.2
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 数据库链接状态确认 { class DBmsql : Singleton<DBmsql> { List<DBmsqlSub> dBmsqlSubs = new List<DBmsqlSub>(); /// <summary> /// 执行sql命令 /// </summary> /// <param name="CommandText"></param> public void ExecuteNonQuery(String CommandText) { getDBmsqlSub().ExecuteNonQuery(CommandText); } /// <summary> /// 插入数据,并返回插入数据的id /// </summary> /// <param name="CommandText"></param> /// <returns></returns> public int insertReturn(string CommandText) { int ret = getDBmsqlSub().insertReturn(CommandText); return ret; } /// <summary> /// 执行并返回一个对象 /// </summary> /// <param name="CommandText"></param> /// <returns></returns> public object ExecuteScalar(string CommandText) { object o = getDBmsqlSub().ExecuteScalar(CommandText); return o; } /// <summary> /// 获取数据处理对象 /// </summary> /// <returns></returns> private DBmsqlSub getDBmsqlSub() { DBmsqlSub ret = null; lock (dBmsqlSubs) { //避免两个同时取到允许的状态 foreach (DBmsqlSub dBmsqlSub in dBmsqlSubs) { if (!dBmsqlSub.IsUrse()) { ret = dBmsqlSub; dBmsqlSub.setIsUser(true); Console.WriteLine("get:" + ret.id); break; } } //避免两个同时创建对象,产生结果列表的错误 if (ret == null&& dBmsqlSubs.Count<90) { DBmsqlSub dBmsqlSub = new DBmsqlSub(); dBmsqlSubs.Add(dBmsqlSub); dBmsqlSub.setIsUser(true); ret = dBmsqlSub; Console.WriteLine("get:" + ret.id); } } return ret; } } }
2.3.3
using MySqlConnector; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 数据库链接状态确认 { public class Constand { public static string mesConnStr = "server=localhost;port=3306;database=db1;user id=root;password=123456;Charset=utf8;"; } class DBmsqlSub { static int index = 0; public int id = 0; private bool isUser = false; private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); MySqlConnection mConn; MySqlCommand mCmd; public void setIsUser(bool value) { lock (this) { Console.WriteLine("index:" + index + " isuser:" + isUser+" setuser:"+ value); isUser = value; } } public MySqlDataReader MySqlDataReader { get; private set; } public DBmsqlSub() { id = index++; try { mConn = new MySqlConnection(Constand.mesConnStr); mConn.Open(); mCmd = new MySqlCommand(); mCmd.Connection = mConn; } catch (Exception e) { logger.Error(e.ToString()); } } ~DBmsqlSub() { mConn.Close(); } public void Close() { mConn.Close(); } public bool isOpen() { if (mConn.State == ConnectionState.Closed) { mConn.Open(); } if (mConn.State == ConnectionState.Open) { return true; } else { return false; } } public MySqlCommand getCmd() { return mCmd; } /// <summary> /// 如果没有链接,就直接链接 /// </summary> private void conn() { if (mConn.State != ConnectionState.Open) { mConn.Open(); } } /// <summary> /// 执行sql命令 /// </summary> /// <param name="CommandText"></param> public void ExecuteNonQuery(String CommandText) { //setIsUser(true); mCmd.CommandText = CommandText; try { Console.WriteLine("id"+id); mCmd.ExecuteNonQuery(); } catch (Exception ex) { logger.Error(ex.ToString()); } finally { setIsUser(false); } } /// <summary> /// 插入数据,并返回插入数据的id /// </summary> /// <param name="CommandText"></param> /// <returns></returns> public int insertReturn(string CommandText) { setIsUser(true); int ret = 0; MySqlTransaction sqlTransaction = mConn.BeginTransaction(); try { mCmd.CommandText = CommandText; object o = mCmd.ExecuteScalar(); sqlTransaction.Commit(); ret = int.Parse(o.ToString()); } catch (Exception e) { logger.Error(e.ToString()); sqlTransaction.Rollback(); } finally { setIsUser(false); } return ret; } /// <summary> /// 执行并返回一个对象 /// </summary> /// <param name="CommandText"></param> /// <returns></returns> public object ExecuteScalar(string CommandText) { setIsUser(true); object o = null; mCmd.CommandText = CommandText; try { o = mCmd.ExecuteScalar(); } catch (Exception ex) { logger.Error(ex.ToString()); } finally { setIsUser(false); } return o; } public MySqlDataReader ExecuteReader(string CommandText) { setIsUser(true); MySqlDataReader mySqlDataReader = null; mCmd.CommandText = CommandText; try { mySqlDataReader = mCmd.ExecuteReader(); //mConn.Close(); } catch (Exception ex) { logger.Error(ex.ToString()); } finally { setIsUser(false); } return mySqlDataReader; } public ConnectionState getState() { return mConn.State; } public bool IsUrse() { return isUser; } } }
2.3.4
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 数据库链接状态确认 { /// <summary> /// 单件构象基类 /// </summary> /// <typeparam name="T"></typeparam> public class Singleton<T> where T : new() { static T t = default(T); public static T getMy() { if (t == null) { t = new T(); } return t; } } }
运行结果:可用看出是几个链接对象在被循环的使用,也基本达到了直接的初衷,用尽可能少的链接,完成多线程的调用情景。
id2 index:5 isuser:True setuser:False index:5 isuser:False setuser:True index:5 isuser:True setuser:False get:3 id3 index:5 isuser:False setuser:True get:4 id4 index:5 isuser:True setuser:False index:5 isuser:False setuser:True get:2 id2 index:5 isuser:True setuser:False index:5 isuser:False setuser:True get:3 id3