背景描述,一個商城網站,一個訂單支付方案有多個1.金額支付2.積分支付3.工資支付(分期和全額),所以一個訂單的方案可能有1;有1、2,或1、2、3
狀態,1.訂單狀態,2,支付狀態==>多方案的訂單有多個支付狀態。
問題發現,一個訂單多次支付!!!
於是分析,找解決方案。
1.DB 行鎖
2.多線程控制
多線程測試參考 鏈接

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleThread { class Program { const string firstOrderId = "001"; const string secondOrderId = "002"; const string thirdOrderId = "003"; static void Main(string[] args) { test(LockType.LockObject); test(LockType.LockStaticObject); test(LockType.LockString); test(LockType.LockThis); } static void test(LockType lockType) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("----------------測試相同的訂單-------------------"); Console.ForegroundColor = ConsoleColor.Green; OrderPay(firstOrderId, 1, lockType); OrderPay(firstOrderId, 2, lockType); OrderPay(firstOrderId, 3, lockType); Thread.Sleep(1000); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("----------------測試不同的訂單-------------------"); Console.ForegroundColor = ConsoleColor.Green; OrderPay(firstOrderId, 1, lockType); OrderPay(secondOrderId, 1, lockType); OrderPay(thirdOrderId, 1, lockType); } static void OrderPay(string orderId, int threadNo, LockType lockType) { new Thread(() => new Payment(orderId, threadNo).Pay(lockType)).Start(); Thread.Sleep(100); } } public class Payment { private readonly string LockString; private readonly int ThreadNo; private readonly Object LockObj = new object(); private static readonly Object StaticLockObj = new object(); public Payment(string orderId, int threadNo) { this.LockString = orderId; this.ThreadNo = threadNo; } public void Pay(LockType lockType) { ShowMessage("等待資源"); switch (lockType) { case LockType.LockThis: lock (this) { ShowAction(); } break; case LockType.LockString: lock (LockString) { ShowAction(); } break; case LockType.LockObject: lock (LockObj) { ShowAction(); } break; case LockType.LockStaticObject: lock (StaticLockObj) { ShowAction(); } break; default: break; } ShowMessage("釋放資源"); } private void ShowAction() { ShowMessage("進入鎖並開始操作"); Thread.Sleep(1000); ShowMessage("完成操作,時間" + DateTime.Now); } private void ShowMessage(string message) { Console.WriteLine(string.Format("訂單{0}的第{1}個線程{2}", LockString, ThreadNo, message)); } } public enum LockType { LockThis = 0, LockString = 1, LockObject = 2, LockStaticObject = 3 } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleThread2 { class Program { /// <summary> /// 訂單號 /// </summary> const string firstOrderId = "d001"; const string secondOrderId = "d002"; const string thirdOrderId = "d003"; const string fourthOrderId = "d004"; const string fivthOrderId = "d005"; static void Main(string[] args) { Test(); } static void Test() { ConsoleOut.WriteWhite("----------------測試-------------------"); //相同的訂單 一個一個來 OrderPay(firstOrderId, 1); OrderPay(firstOrderId, 2); OrderPay(firstOrderId, 3); OrderPay(firstOrderId, 4); //不同的訂單可以同時處理 OrderPay(secondOrderId, 5); OrderPay(thirdOrderId, 6); OrderPay(fourthOrderId, 7); OrderPay(fivthOrderId, 8); } /// <summary> /// 多線程支付 /// </summary> /// <param name="orderId">訂單號</param> /// <param name="threadNo">線程編號</param> static void OrderPay(string orderId, int threadNo) { new Thread((object x) => Payment.Pay(new object[] { orderId, threadNo })).Start(); } } /// <summary> /// 鎖字典一個訂單對映一個鎖 /// </summary> public static class DicLockManage { /// <summary> /// 根據訂單id得到,鎖資源 /// </summary> public static Dictionary<string, object> dicLock = new Dictionary<string, object>(); /// <summary> /// 字典操作的鎖 /// </summary> public static readonly object objLock = new object(); /// <summary> /// 得到訂單鎖 /// </summary> /// <param name="key"></param> /// <returns></returns> public static object GetKeyValue(string key) { lock (objLock) { if (dicLock.ContainsKey(key)) { return dicLock[key]; } else { dicLock.Add(key, new object()); return GetKeyValue(key); } } } } /// <summary> /// 訂單支付類 /// </summary> public static class Payment { /// <summary> /// 模擬支付方法 /// </summary> /// <param name="objParams"></param> public static void Pay(object[] objParams) { object[] Params = objParams as object[]; string OrderId = Params[0].ToString(); int ThreadNo = Convert.ToInt32(Params[1]); //加鎖 lock (DicLockManage.GetKeyValue(OrderId)) { ShowMessage(OrderId, ThreadNo, "等待資源"); ShowAction(OrderId, ThreadNo);//模擬支付 ShowMessage(OrderId, ThreadNo, "釋放鎖"); } } private static void ShowAction(string OrderId, int ThreadNo) { ShowMessage(OrderId, ThreadNo, "進入鎖並開始操作"); ConsoleOut.WriteRed("線程" + ThreadNo + "處理中..."); Thread.Sleep(3000); ConsoleOut.WriteGreen("線程" + ThreadNo + "完成處理..."); ShowMessage(OrderId, ThreadNo, "完成操作,時間" + DateTime.Now); } private static void ShowMessage(string OrderId, int ThreadNo, string message) { ConsoleOut.WriteYellow(string.Format("訂單{0}的第{1}個線程{2}", OrderId, ThreadNo, message)); } } /// <summary> /// 輸出類,設置顏色 /// </summary> public static class ConsoleOut { public static void WriteWhite(string message) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(message); } public static void WriteRed(string message) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); } public static void WriteYellow(string message) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(message); } public static void WriteGreen(string message) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(message); } } }
測試圖
1.同一個訂單多個線程訪問,一個個處理

2.多個訂單多個線程,可以一起處理,完成的時間一樣
3.同時運行
如有問題,請指出。