c#实现用SQL池(多线程),批量执行SQL语句

在实际项目开发中,业务逻辑层的处理速度往往很快,特别是在开发Socket通信服务的时候,网络传输很快,但是一旦加上数据库操作,性能一落千丈,数据库操作的效率往往成为一个系统整体性能的瓶颈。面对这问题,我们怎么办呢?好,下面我就为大家介绍一种方法:构建SQL池,分离业务逻辑层和数据访问层,让业务逻辑层从低效的数据库操作解脱,以提高系统整体性能。


(一)SQL池


  SQL池是SQL容器,用于存放业务逻辑层抛过来的SQL语句。SQL池主要提供以下几种方法:


1)internal string Pop(),从池中取出SQL。


2)internal void Push(string item),增加一个SQL到池中。


3)internal string[] Clear(),清空SQL池,清空前,返回SQL池中所有SQL语句。


  特别提醒一下,SQL池是面向多线程的,所以必须对公共资源SQL采取锁机制。这里采用互斥锁,当业务逻辑层线程往SQL池中抛入SQL语句时,禁止SQL执行线程执行SQL语句,反之,当SQL执行线程执行SQL语句时,也不允许业务逻辑层线程往SQL池中抛入SQL语句。为什么要这么做?因为SQL执行线程是批量执行SQL语句,在批量执行SQL语句前,会从池中取出所有SQL语句,如果此时业务逻辑层线程往SQL池中抛入SQL语句,则会导致这些SQL语句丢失,得不到执行。


下面是SQL池代码:
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
  
namespace Test1 

    sealed class SQLPool 
    { 
        //互斥锁 
        public static Mutex mutexSQLPool = new Mutex(); 
  
        //SQL池 
        Stack<string> pool; 
  
        /// <summary> 
        /// 初始化SQL池 
        /// </summary> 
        internal SQLPool() 
        { 
            this.pool = new Stack<string>(); 
        } 
  
  
        /// <summary> 
        /// 获取SQL池数量 
        /// </summary> 
        internal Int32 Count 
        { 
            get { return this.pool.Count; } 
        } 
  
  
        /// <summary> 
        /// 从池中取出SQL 
        /// </summary> 
        /// <returns></returns> 
        internal string Pop() 
        { 
            lock (this.pool) 
            { 
                return this.pool.Pop(); 
            } 
        } 
  
  
        /// <summary> 
        /// 增加一个SQL到池中 
        /// </summary> 
        /// <param name="item"></param> 
        internal void Push(string item) 
        { 
            if (item.Trim() == "") 
            { 
                throw new ArgumentNullException("Items added to a SQLPool cannot be null"); 
            } 
  
            //此处向SQL池中push SQL必须与Clear互斥 
            mutexSQLPool.WaitOne(); 
            try
            { 
                this.pool.Push(item);    //此处如果出错,则不会执行ReleaseMutex,将会死锁 
            } 
            catch
            {  
            } 
            mutexSQLPool.ReleaseMutex(); 
        } 
  
  
        /// <summary> 
        /// 清空SQL池 
        /// 清空前,返回SQL池中所有SQL语句, 
        /// </summary> 
        internal string[] Clear() 
        { 
            string[] array = new string[] { }; 
  
            //此处必须与Push互斥 
            mutexSQLPool.WaitOne(); 
            try
            { 
                array = this.pool.ToArray();     //此处如果出错,则不会执行ReleaseMutex,将会死锁 
                this.pool.Clear(); 
            } 
            catch
            {  
            } 
            mutexSQLPool.ReleaseMutex(); 
  
            return array; 
        } 
    } 
}
 


(二)SQL池管理


  SQL池管理主要用于管理SQL池,向业务逻辑层线程和SQL执行线程提供接口。


  业务逻辑层线程调用 public void PushSQL(string strSQL) 方法,用于向SQL池抛入SQL语句。


  SQL执行线程调用 public void ExecuteSQL(object obj) 方法,用于批量执行SQL池中的SQL语句。


  注意,SQL池管理类采用单例模型,为什么要采用单例模型?因为SQL池只能存在一个实例,无论是业务逻辑层线程还是SQL执行线程,仅会操作这一个实例,否则,将会导致SQL池不唯一,SQL执行无效。


  下面是SQL池管理类代码:


 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
  
namespace Test1 

    class SQLPoolManage 
    { 
        //单例模型 
        public static readonly SQLPoolManage sqlPoolManage = new SQLPoolManage(); 
  
        #region 属性 
        SQLPool poolOfSQL; 
        #endregion 
  
  
        #region 构造函数 
        /// <summary> 
        /// 初始化 
        /// </summary> 
        public SQLPoolManage() 
        { 
            this.poolOfSQL = new SQLPool(); 
        } 
        #endregion 
  
  
        #region 方法 
        /// <summary> 
        /// 将SQL语句加入SQL池中 
        /// </summary> 
        /// <param name="strSQL"></param> 
        public void PushSQL(string strSQL) 
        { 
            this.poolOfSQL.Push(strSQL); 
        } 
  
  
        /// <summary> 
        /// 每隔一段时间,触发ExecuteSQL 
        /// ExecuteSQL用于执行SQL池中的SQL语句 
        /// </summary> 
        /// <param name="obj"></param> 
        public void ExecuteSQL(object obj) 
        { 
            if (this.poolOfSQL.Count > 0) 
            { 
                string[] array = this.poolOfSQL.Clear(); 
                //遍历array,执行SQL 
                for (int i = 0; i < array.Length; i++) 
                { 
                    if (array[i].ToString().Trim() != "") 
                    { 
                        try
                        { 
                            //数据库操作 
                            //...... 
                        } 
                        catch
                        {  
                        } 
                    } 
                } 
            } 
        } 
        #endregion 
  
    } 
}
 


 


(三)定时触发SQL执行线程


  总结有以下三种方法,具体请参见http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813928.html:


方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间;


方法二:使用System.Timers.Timer类;


方法三:使用System.Threading.Timer;


  代码如下:


 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
  
using System.Threading; 
  
namespace Test1 

  
    class Program 
    { 
        static void Main(string[] args) 
        { 
            //向SQL池中抛入SQL语句 
            SQLPoolManage.sqlPoolManage.PushSQL("delete from tbl_test where id = 1"); 
  
            //定时触发SQL执行线程 
            System.Threading.Timer threadTimer = new System.Threading.Timer(new System.Threading.TimerCallback(SQLPoolManage.sqlPoolManage.ExecuteSQL), null, 0, 100); 
  
            Console.ReadLine(); 
        } 
    } 
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C# 使用多线程读取 SQL Server 数据库表的信息,可以使用以下步骤: 1. 创建一个 SQL 连接对象,并打开连接。 2. 创建一个 SQL 命令对象,并设置 SQL 查询语句。 3. 创建一个 SQL 数据适配器对象,并将 SQL 命令对象作为参数进行设置。 4. 创建一个数据表对象,用于存储查询结果。 5. 创建多个线程对象,并为每个线程分配一个任务。 6. 在每个线程使用 SQL 数据适配器对象来填充数据表对象。 7. 在主线程等待所有线程完成任务,并合并所有数据表对象。 下面是示例代码: ```csharp using System; using System.Data.SqlClient; using System.Data; using System.Threading; public class Program { static void Main(string[] args) { string connectionString = "Data Source=serverName;Initial Catalog=databaseName;Integrated Security=True;"; string query = "SELECT * FROM tableName;"; SqlConnection connection = new SqlConnection(connectionString); connection.Open(); SqlCommand command = new SqlCommand(query, connection); SqlDataAdapter adapter = new SqlDataAdapter(command); DataTable table = new DataTable(); Thread[] threads = new Thread[5]; for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(() => { adapter.Fill(table); }); threads[i].Start(); } foreach (Thread thread in threads) { thread.Join(); } // Merge all tables DataTable mergedTable = new DataTable(); foreach (DataColumn column in table.Columns) { mergedTable.Columns.Add(column.ColumnName, column.DataType); } foreach (DataRow row in table.Rows) { mergedTable.ImportRow(row); } connection.Close(); } } ``` 在上面的示例代码,我们使用了 5 个线程来读取数据表的信息,并将结果存储在一个数据表对象。最后,我们合并了所有数据表对象,得到了完整的查询结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值