相信这个问题不止小编一个人遇到,这个问题可大可小;如果你还没有修复这个BUG,请认真看完这篇文章;
首先我们来看一下DTcms自带的生成订单号的方法中
/// <summary> /// 根据日期和随机码生成订单号 /// </summary> /// <returns></returns> public static string GetOrderNumber() { string num = DateTime.Now.ToString("yyMMddHHmmss");//yyyyMMddHHmmssms return num + Number(2, true).ToString(); } /// <summary> /// 生成随机数字 /// </summary> /// <param name="Length">生成长度</param> /// <param name="Sleep">是否要在生成前将当前线程阻止以避免重复</param> /// <returns></returns> public static string Number(int Length, bool Sleep) { if (Sleep) System.Threading.Thread.Sleep(3); string result = ""; System.Random random = new Random(); for (int i = 0; i < Length; i++) { result += random.Next(10).ToString(); } return result; }
我们可以看到,这里用到了线程等待,但是这根本解决不了问题;我们通过模拟50个线程来获取订单号
static void Main(string[] args) { for (int i = 0; i < 50; i++) { // 并发启动多线程 Thread thread = new Thread(new ThreadStart(GetUserRoleName)); thread.Start(); } Console.Read(); } private static void GetUserRoleName() { Console.WriteLine(GetOrderNumber()); }
从输出的结果中,我们可以看出,输出的订单号,大部分都是重复的;现在我们将线程数改为10个,在来看看;
可以看出基本上全是一样的;现在我们来说说如何修复这个问题,在数据库中,限制订单表中的订单号唯一约束
--增加订单号唯一约束 ALTER TABLE dt_orders ADD CONSTRAINT AK_DT_ORDERS_ORDERNO UNIQUE (order_no);
这样可以保证我们数据表中不会有重复的订单号,但是程序中我们还没有解决,接下来借鉴其它项目中的一种方法,代码如下
/// <summary> /// 工具类 /// </summary> public class Utils { private static object Orderidlock = new object(); private static string provOrderid = ""; /// <summary> /// 获取不重复订单号 /// </summary> /// <returns></returns> public static string GetOrderNumber() { string result; lock (Orderidlock) { string str = DateTime.Now.ToString("yyMMddHHmmssfff"); if (str == provOrderid) { Thread.Sleep(1); str = DateTime.Now.ToString("yyMMddHHmmssfff"); } provOrderid = str; result = str; } return result; } }
这种方是利用了静态变量的特性,不过这种方法只能用对于单节服务器;
当然如果在多节点服务器中的每个服务器的订单前增加一个字符或字符串,如:1号服务器前缀用A,2号服务器前缀用B,3号服务器前缀用C,这样不同服务器上生成的订单号就是:A***、B***、C***。