• 多进程用户并发处理Demo(C#版)


    这个示例主要演示的是在多进程操作数据库时,如何避免并发重复数据入库的例子。

    过多的线程理论不再阐述,网上、书上皆有。

    项目采用 Asp.Net Framework 4.5 / Mysql 5.4 数据库。

    首先创建一个 LockInsertDB.cs 文件,这个文件用来实现数据库添加; 

     1 using System;
     2 using MySql;
     3 using MySql.Data.MySqlClient;
     4 using System.Collections.Generic;
     5 using System.Linq;
     6 using System.Text;
     7 using System.Threading.Tasks;
     8 
     9 namespace DBImportTool
    10 {
    11     public class LockInsertDB : Common
    12     {
    13         private object obj = new object();
    14         /// <summary>
    15         /// 添加测试数据
    16         /// </summary>
    17         /// <param name="path">字段内容</param>
    18         /// <param name="tname">线程名称</param>
    19         public void InsertTestDB(string path, object tname)
    20         {
    21             MySql.Data.MySqlClient.MySqlConnection conn = new MySql.Data.MySqlClient.MySqlConnection("Server=10.17.1.57; Database=videodb; Uid=root; Pwd=xingzhi");
    22             try
    23             {
    24                 conn.Open();//打开连接
    25                 MySql.Data.MySqlClient.MySqlCommand cmd = new MySql.Data.MySqlClient.MySqlCommand();
    26                 cmd.Connection = conn;
    27                 //加入多线程,排它锁机制.
    28                 lock (obj)
    29                 {
    30                     string select = "SELECT * FROM `tbl_test` WHERE `filepath` = '" + path + "'";
    31                     cmd.CommandText = select;
    32                     object val = cmd.ExecuteScalar();
    33                     if (val == null)
    34                     {
    35                         string sql = "INSERT INTO `tbl_test` (`filepath`, `addtime`) VALUES ('" + path + "', NOW());";
    36                         cmd.CommandText = sql;
    37                         cmd.ExecuteNonQuery();
    38                         P(DateTime.Now.ToString() + " " + tname + " OK " + path + " ");
    39                     }
    40                     else
    41                     {
    42                         P(DateTime.Now.ToString() + " " + tname + " 已存在 " + path + " ");
    43                     }
    44                 }
    45             }
    46             catch
    47             {
    48 
    49             }
    50             finally
    51             {
    52                 //关闭连接
    53                 conn.Close();
    54             }
    55         }
    56         /// <summary>
    57         /// 测试输出
    58         /// </summary>
    59         /// <param name="str">输出内容字符串</param>
    60         public void P(string str)
    61         {
    62             Console.Write(str);
    63         }
    64     }

    65 } 

    再创建一个控制台工程,Main方法代码如下:

     1 using System;
     2 using System.Threading;
     3 using System.IO;
     4 using System.Collections.Generic;
     5 using System.Linq;
     6 using System.Text;
     7 using System.Threading.Tasks;
     8 namespace DBImportTool
     9 {
    10     public class Mcqueen
    11     {
    12         static void Main(string[] args)
    13         {
    14             Run();
    15             Console.ReadLine();
    16         }
    17         /// <summary>
    18         /// 进程数量.
    19         /// </summary>
    20         static int tnum = 2;
    21         /// <summary>
    22         /// 所对象
    23         /// </summary>
    24         static object obj = new object();
    25         /// <summary>
    26         /// 线程数组.
    27         /// </summary>
    28         static Thread[] threadarr = new Thread[tnum];
    29         /// <summary>
    30         /// 数据库插入对象.
    31         /// </summary>
    32         static LockInsertDB mdb = new LockInsertDB();
    33         /// <summary>
    34         /// 运行函数
    35         /// </summary>
    36         public static void Run()
    37         {
    38             for (int i = 0; i < tnum; i++)
    39             {
    40                 Thread t = new Thread(T1);
    41                 threadarr[i] = t;
    42                 threadarr[i].Name = "Thread " + i.ToString() + " :";
    43             }
    44             int y = 0;
    45             while (y < tnum)
    46             {
    47                 threadarr[y].Start(threadarr[y].Name);
    48                 y++;
    49             }
    50         }
    51         /// <summary>
    52         /// 读取磁盘文件路径.
    53         /// </summary>
    54         /// <param name="tname">线程名称</param>
    55         public static void T1(object tname)
    56         {
    57             DirectoryInfo di = Directory.CreateDirectory(@"F:邢智的文件");
    58             GetFiles(di, tname);
    59         }
    60         /// <summary>
    61         /// 采用对列入栈模式对列遍历文件夹结构.
    62         /// </summary>
    63         /// <param name="di">目录对象</param>
    64         /// <param name="tobj">线程名称</param>
    65         private static void GetFiles(DirectoryInfo di,object tobj)
    66         {
    67             int sgin = 1;
    68             Stack<DirectoryInfo> stack_dir = new Stack<DirectoryInfo>();
    69             DirectoryInfo dir = di;
    70             stack_dir.Push(di);
    71             while (stack_dir.Count != 0)
    72             {
    73                 dir = stack_dir.Pop();
    74                 DirectoryInfo[] diarr = dir.GetDirectories();
    75                 foreach (DirectoryInfo d in diarr)
    76                     stack_dir.Push(d);
    77                 FileInfo[] files = dir.GetFiles();
    78                 foreach (FileInfo f in files)
    79                 {
    80                     mdb.InsertTestDB(f.FullName.Replace("\""\\"), tobj);
    81                     Thread.Sleep(200);
    82                     sgin++;
    83                 }
    84             }
    85         }
    86         public static void P(string str)
    87         {
    88             Console.Write(str);
    89         }
    90     }

    91 } 


    static LockInsertDB mdb = new LockInsertDB();

    一开始把这句初始化对象放到了private static void GetFiles(DirectoryInfo di,object tobj) 函数里面,虽然在后续的执行过程中没有任何问题,

    但是初始化运行线程时导致了进程并发进入lock锁中,后来研究一下原因,是因为每个进程都在实例化化它的时候都会在lock中分配一个标识符,

    这样一来,假如A进程内实例化了A1,那么当B进程进来之后,B却不认识A线程内的A1,因此lock也就对A1不起作用了。

    因此把这个类跳出线程而放到一个全局中去实例化,也就不存在这个lock失效的问题了。

    运行结果如下: 

    如果需要模拟更多的进程用户,只需要把 tnum = 2 的数值改一下即可。 

  • 相关阅读:
    Windows 7 x64 (英文操作系统)安装SQLServer 2005版本相关解决方法
    vs2008打开vs2010所做的项目的方法
    sqlserver2008 创建自动备份任务(图文教程)
    js返回上一页,自动刷新自身、父页面语句的实现
    有效的更改IE、Firefox、Chrome浏览器缓存位置的方法
    oo第二次总结
    OO第一次博客总结
    Ansible常用命令整理
    APM全链路监控日志收集篇
    TCP 和 UDP 的区别还有一个UTP一
  • 原文地址:https://www.cnblogs.com/mcqueen/p/4024946.html
Copyright © 2020-2023  润新知