最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于C#解決庫(kù)存扣減及訂單創(chuàng)建時(shí)防止并發(fā)死鎖的問(wèn)題

 更新時(shí)間:2022年05月27日 14:04:12   作者:tansar  
這篇文章主要介紹了基于C#解決庫(kù)存扣減及訂單創(chuàng)建時(shí)防止并發(fā)死鎖的問(wèn)題,很多開(kāi)發(fā)人員對(duì)于這個(gè)問(wèn)題的排查起來(lái)是比較困難的,而生產(chǎn)生的原因多種多樣,很多人認(rèn)是因?yàn)楸碇械臄?shù)據(jù)太多了同時(shí)操作的人多人才會(huì)產(chǎn)生這種錯(cuò)誤,下面我們來(lái)還原一下死鎖的過(guò)程

解決庫(kù)存扣減及訂單創(chuàng)建時(shí)防止并發(fā)死鎖的問(wèn)題

在我們?nèi)粘i_(kāi)發(fā)的過(guò)程可有會(huì)遇到以下錯(cuò)誤

事務(wù)(進(jìn)程 ID 82)與另一個(gè)進(jìn)程被死鎖在 鎖 資源上,并且已被選作死鎖犧牲品。請(qǐng)重新運(yùn)行該事務(wù)

很多開(kāi)發(fā)人員對(duì)于這個(gè)問(wèn)題的排查起來(lái)是比較困難的,而生產(chǎn)生的原因多種多樣,很多人認(rèn)是因?yàn)楸碇械臄?shù)據(jù)太多了同時(shí)操作的人多人才會(huì)產(chǎn)生這種錯(cuò)誤,下面我們來(lái)還原一下死鎖的過(guò)程。

我們看一下以下sql代碼(該樣例代碼測(cè)試環(huán)境為SqlServer)

1. 第一先創(chuàng)建一個(gè)測(cè)試表H_Test

復(fù)制以下代碼

  SET ANSI_NULLS ON
  GO
  SET QUOTED_IDENTIFIER ON
  GO
  CREATE TABLE [dbo].[H_TEST](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [DID] [int] NULL,
    [UNAME] [nvarchar](50) NULL,
    [UNAME2] [nvarchar](50) NULL,
  CONSTRAINT [PK_H_TEST_3994ceeb-a4b8-41e1-b06b-1e59a2e51d8c] PRIMARY KEY CLUSTERED 
  (
    [Id] ASC
  )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  ) ON [PRIMARY]
  GO
  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'自增主鍵' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_TEST', @level2type=N'COLUMN',@level2name=N'Id'
  GO
  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'DID' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_TEST', @level2type=N'COLUMN',@level2name=N'DID'
  GO
  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'UNAME' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_TEST', @level2type=N'COLUMN',@level2name=N'UNAME'
  GO
  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'UNAME2' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_TEST', @level2type=N'COLUMN',@level2name=N'UNAME2'
  GO
  insert [dbo].[H_TEST](DID,UNAME,UNAME2) VALUES(1,'HI','HI2');
  insert [dbo].[H_TEST](DID,UNAME,UNAME2) VALUES(2,'HISQL','HISQL2');

2. 打開(kāi)兩個(gè)查詢窗口

在窗口1中復(fù)制以下代碼

 begin tran 
  update dbo.H_TEST 
  set UNAME='d1' 
  where dID=1 
  waitfor delay '00:00:10' 
  update H_TEST 
  set UNAME='d2' 
  where dID=2
  commit tran 

在窗口2中復(fù)制以下代碼

begin tran 
  update H_TEST 
  set UNAME='d2' 
  where dID=2
  waitfor delay '00:00:10' 
  update dbo.H_TEST 
  set UNAME='d1' 
  where dID=1
  commit tran 

3. 執(zhí)行代碼

同時(shí)執(zhí)行窗口1和窗口2的代碼,在等待一段時(shí)間后你就可以看到以下錯(cuò)誤如下所示

通過(guò)以上的測(cè)試就還原了產(chǎn)生死鎖的過(guò)程,剛才的測(cè)試表H_Test中只有兩條數(shù)據(jù),其實(shí)產(chǎn)生死鎖與數(shù)據(jù)大小沒(méi)有很大的關(guān)系,其實(shí)與整個(gè)事務(wù)的執(zhí)行長(zhǎng)短有關(guān)系,兩個(gè)業(yè)務(wù)都在操作同一條數(shù)據(jù),且一個(gè)事務(wù)中包含非常復(fù)雜的處理邏輯且執(zhí)行時(shí)間比較長(zhǎng)那么在并發(fā)或相對(duì)較多的業(yè)務(wù)操作時(shí)就會(huì)產(chǎn)生死鎖。

那么怎樣解決死鎖?

1. 減少事務(wù)的執(zhí)行時(shí)間。

優(yōu)化代碼將不需要包在事務(wù)的邏輯分離出來(lái)以減少鎖的占用時(shí)間.可以減少一部分的死鎖,但在高并發(fā)操作時(shí)依然會(huì)產(chǎn)生死鎖

2. 業(yè)務(wù)鎖

日常我們用到的鎖都是高度依賴于數(shù)據(jù)來(lái)鎖定來(lái)保證數(shù)據(jù)的原子性問(wèn)題,但這樣有一個(gè)很大的BUG就是對(duì)數(shù)據(jù)庫(kù)的性能壓力非常大,在出現(xiàn)高并發(fā)時(shí)可能應(yīng)用扛得住數(shù)據(jù)庫(kù)扛不住的情況

下面介紹的就是基于HiSql 的業(yè)務(wù)鎖機(jī)制解決死鎖問(wèn)題,我們模擬一種場(chǎng)景 扣減庫(kù)存并生成訂單那么我們模擬創(chuàng)建兩張表 庫(kù)存表H_Stock 及訂單表H_Order 表創(chuàng)建的sql如下

HiSql怎樣使用 請(qǐng)參照hisql快速上手

庫(kù)存表sql代碼

CREATE TABLE [dbo].[H_Stock](
    [Batch] [varchar](20) NOT NULL,
    [Material] [varchar](20) NOT NULL,
    [Location] [varchar](5) NULL,
    [st_kc] [decimal](18, 2) NULL,
    [CreateTime] [datetime] NULL,
    [CreateName] [nvarchar](50) NULL,
    [ModiTime] [datetime] NULL,
    [ModiName] [nvarchar](50) NULL,
  CONSTRAINT [PK_H_Stock] PRIMARY KEY CLUSTERED 
  (
    [Batch] ASC,
    [Material] ASC
  )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  ) ON [PRIMARY]
  GO

  ALTER TABLE [dbo].[H_Stock] ADD  CONSTRAINT [DF_H_Stock_st_kc]  DEFAULT ((0)) FOR [st_kc]
  GO

  ALTER TABLE [dbo].[H_Stock] ADD  CONSTRAINT [DF_H_Stock_CreateTime]  DEFAULT (getdate()) FOR [CreateTime]
  GO

  ALTER TABLE [dbo].[H_Stock] ADD  CONSTRAINT [DF_H_Stock_CreateName]  DEFAULT ('') FOR [CreateName]
  GO

  ALTER TABLE [dbo].[H_Stock] ADD  CONSTRAINT [DF_H_Stock_ModiTime]  DEFAULT (getdate()) FOR [ModiTime]
  GO

  ALTER TABLE [dbo].[H_Stock] ADD  CONSTRAINT [DF_H_Stock_ModiName]  DEFAULT ('') FOR [ModiName]
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'批次號(hào)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'Batch'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'款號(hào)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'Material'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'庫(kù)位' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'Location'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'庫(kù)存數(shù)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'st_kc'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'創(chuàng)建時(shí)間' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'CreateTime'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'創(chuàng)建人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'CreateName'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改時(shí)間' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'ModiTime'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Stock', @level2type=N'COLUMN',@level2name=N'ModiName'
  GO

訂單表sql

 CREATE TABLE [dbo].[H_Order](
    [OrderId] [bigint] NOT NULL,
    [Batch] [varchar](20) NOT NULL,
    [Material] [varchar](20) NOT NULL,
    [Shop] [varchar](5) NULL,
    [Location] [varchar](5) NULL,
    [SalesNum] [decimal](18, 2) NULL,
    [CreateTime] [datetime] NULL,
    [CreateName] [nvarchar](50) NULL,
    [ModiTime] [datetime] NULL,
    [ModiName] [nvarchar](50) NULL,
  CONSTRAINT [PK_H_Order] PRIMARY KEY CLUSTERED 
  (
    [OrderId] ASC,
    [Batch] ASC,
    [Material] ASC
  )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  ) ON [PRIMARY]
  GO

  ALTER TABLE [dbo].[H_Order] ADD  CONSTRAINT [DF_H_Order_SalesNum]  DEFAULT ((0)) FOR [SalesNum]
  GO

  ALTER TABLE [dbo].[H_Order] ADD  CONSTRAINT [DF_H_Order_CreateTime]  DEFAULT (getdate()) FOR [CreateTime]
  GO

  ALTER TABLE [dbo].[H_Order] ADD  CONSTRAINT [DF_H_Order_CreateName]  DEFAULT ('') FOR [CreateName]
  GO

  ALTER TABLE [dbo].[H_Order] ADD  CONSTRAINT [DF_H_Order_ModiTime]  DEFAULT (getdate()) FOR [ModiTime]
  GO

  ALTER TABLE [dbo].[H_Order] ADD  CONSTRAINT [DF_H_Order_ModiName]  DEFAULT ('') FOR [ModiName]
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'批次號(hào)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'Batch'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'款號(hào)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'Material'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'門(mén)店' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'Shop'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'出庫(kù)庫(kù)位' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'Location'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'銷售數(shù)量' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'SalesNum'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'創(chuàng)建時(shí)間' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'CreateTime'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'創(chuàng)建人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'CreateName'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改時(shí)間' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'ModiTime'
  GO

  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'修改人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'H_Order', @level2type=N'COLUMN',@level2name=N'ModiName'
  GO

測(cè)試場(chǎng)景

開(kāi)啟多個(gè)線程隨機(jī)產(chǎn)生不同的訂單(一個(gè)訂單中有不同批次和數(shù)量)直至庫(kù)存扣減完成并檢測(cè)是否有鎖產(chǎn)生,且?guī)齑嬗袥](méi)有少扣和超扣,如果達(dá)到這兩個(gè)目標(biāo)說(shuō)明測(cè)試是成功的

c# 代碼

class Program
  {
    static void Main(string[] args)
    {
        Console.WriteLine("測(cè)試!");
        StockThread();
        var s = Console.ReadLine();
    }
    static void StockThread()
    {
        //如果有安裝redis可以啟用以下測(cè)試一下
        //HiSql.Global.RedisOn = true;//開(kāi)啟redis緩存
        //HiSql.Global.RedisOptions = new RedisOptions { Host = "172.16.80.178", PassWord = "pwd123", Port = 6379, CacheRegion = "TST", Database = 0 };
        HiSqlClient sqlClient = Demo_Init.GetSqlClient();
        //清除庫(kù)存表和訂單表數(shù)據(jù)
        sqlClient.CodeFirst.Truncate("H_Stock");
        sqlClient.CodeFirst.Truncate("H_Order");
        //初始化庫(kù)存數(shù)據(jù)
        sqlClient.Modi("H_Stock", new List<object> {
            new { Batch="9000112112",Material="ST0021",Location="A001",st_kc=5000},
            new { Batch="8000252241",Material="ST0080",Location="A001",st_kc=1000},
            new { Batch="7000252241",Material="ST0026",Location="A001",st_kc=1500}
        }).ExecCommand();
        //第一種場(chǎng)景 一個(gè)訂單中只有一個(gè)批次
        string[] grp_arr1 = new string[] { "9000112112" };
        //第二種場(chǎng)景 一個(gè)訂單中有兩個(gè)批次
        string[] grp_arr2 = new string[] {  "8000252241" , "9000112112"   };
        //第三中場(chǎng)景一個(gè)訂單中有三個(gè)批次
        string[] grp_arr3 = new string[] { "8000252241", "9000112112", "7000252241" };
        Random random = new Random();
        HiSqlClient _sqlClient = Demo_Init.GetSqlClient();
        //表結(jié)構(gòu)緩存預(yù)熱
        var _dt1= _sqlClient.HiSql("select * from H_Order").Take(1).Skip(1).ToTable();
        var _dt2 = _sqlClient.HiSql("select * from H_Stock").Take(1).Skip(1).ToTable();
        //開(kāi)啟10個(gè)線程運(yùn)行
        Parallel.For(0, 10, (index, y) => {
          int grpidx = index % 3;
          string[] grparr = null;
          if (grpidx == 0)
              grparr = grp_arr1;
          else if (grpidx == 1)
              grparr = grp_arr2;
          else
              grparr = grp_arr3;
          //Thread.Sleep(random.Next(10) * 200);
          Console.WriteLine($" {index}線程Id:{Thread.CurrentThread.ManagedThreadId}\t{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
          //執(zhí)行訂單創(chuàng)建
          var rtn = CreateSale(grparr);
          Console.WriteLine(rtn.Item2);
        });
    }

    static Tuple<bool, string> CreateSale(string[] grparr)
    {
        Random random = new Random();
        HiSqlClient _sqlClient = Demo_Init.GetSqlClient();
        bool _flag = true;
        Tuple<bool, string> rtn = new Tuple<bool, string>(true, "執(zhí)行");
        //指定雪花ID使用的引擎 (可以不指定)
        HiSql.Snowflake.SnowType = SnowType.IdWorker;
        //產(chǎn)生一個(gè)唯一的訂單號(hào)
        Int64 orderid = HiSql.Snowflake.NextId();
        //加鎖并執(zhí)行 將一個(gè)訂單的批次都加鎖防止同一時(shí)間被其它業(yè)務(wù)修改
        var _rtn = HiSql.Lock.LockOnExecute(grparr, () =>
        {
            //能執(zhí)行到此說(shuō)明已經(jīng)加鎖成功(注:非數(shù)據(jù)庫(kù)級(jí)加鎖)
            DataTable dt = _sqlClient.HiSql($"select Batch,Material,Location,st_kc from H_Stock where  Batch in ({grparr.ToSqlIn()}) and st_kc>0").ToTable();
            if (dt.Rows.Count > 0)
            {
                List<object> lstorder = new List<object>();
                Console.WriteLine($"雪花ID{orderid}");
                string _shop = "4301";//門(mén)店編號(hào)
                _sqlClient.BeginTran();
                foreach (string n in grparr)
                {
                    int s = random.Next(1,10);
                    int v = _sqlClient.Update("H_Stock", new { st_kc = $"`st_kc`-{s}" }).Where($"Batch='{n}' and st_kc>={s}").ExecCommand();
                    if (v == 0)
                    {
                        _flag = false;
                        Console.WriteLine($"批次:[{n}]扣減[{s}]失敗");
                        rtn = new Tuple<bool, string>(false, $"批次:[{n}]庫(kù)存已經(jīng)不足");
                        _sqlClient.RollBackTran();
                        break;
                    }
                    else
                    {
                        DataRow _drow = dt.AsEnumerable().Where(s => s.Field<string>("Batch").Equals(n)).FirstOrDefault();
                        if (_drow != null)
                        {
                            lstorder.Add(
                                new
                                {
                                    OrderId = orderid,
                                    Batch = _drow["Batch"].ToString(),
                                    Material = _drow["Material"].ToString(),
                                    Shop = _shop,
                                    Location = _drow["Location"].ToString(),
                                    SalesNum = s,
                                }
                                );
                        }
                        else
                        {
                            _flag = false;
                            Console.WriteLine($"批次:[{n}]扣減[{s}]失敗 未找到庫(kù)存");
                            _sqlClient.RollBackTran();
                            break;
                        }
                    }
                }
                if (_flag)
                {
                    //生成訂單
                    if (lstorder.Count > 0)
                        _sqlClient.Insert("H_Order", lstorder).ExecCommand();
                    _sqlClient.CommitTran();
                }
            }
            else
            {
                Console.WriteLine($"庫(kù)存不足...");
                rtn = new Tuple<bool, string>(false, "庫(kù)存已經(jīng)不足");
            }
        }, new LckInfo
        {
            UName = "tanar",
            Ip = "127.0.0.1"
        }, 20, 10);//加鎖超時(shí)時(shí)間設(shè)定
        _sqlClient.Close();
        Console.WriteLine(_rtn.Item2);
        //可以注釋線程等待
        //Thread.Sleep(random.Next(1,10)*100);
        if (rtn.Item1)
            return CreateSale(grparr);
        else
            return rtn;
    }
  }

數(shù)據(jù)庫(kù)連接配置

 internal class Demo_Init
  {
      public static HiSqlClient GetSqlClient()
      {

          HiSqlClient sqlclient = new HiSqlClient(
                    new ConnectionConfig()
                    {
                        DbType = DBType.SqlServer,
                        DbServer = "local-HoneBI",
                        ConnectionString = "server=(local);uid=sa;pwd=Hone@123;database=HiSql;Encrypt=True; TrustServerCertificate=True;",//; MultipleActiveResultSets = true;
                        User = "tansar",//可以指定登陸用戶的帳號(hào)
                        Schema = "dbo",
                        IsEncrypt = true,
                        IsAutoClose = true,
                        SqlExecTimeOut = 60000,
                        AppEvents = new AopEvent()
                        {
                            OnDbDecryptEvent = (connstr) =>
                            {
                                //解密連接字段
                                //Console.WriteLine($"數(shù)據(jù)庫(kù)連接:{connstr}");
                                return connstr;
                            },
                            OnLogSqlExecuting = (sql, param) =>
                            {
                                //sql執(zhí)行前 日志記錄 (異步)
                                //Console.WriteLine($"sql執(zhí)行前記錄{sql} time:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")}");
                            },
                            OnLogSqlExecuted = (sql, param) =>
                            {
                                //sql執(zhí)行后 日志記錄 (異步)
                                //Console.WriteLine($"sql執(zhí)行后記錄{sql} time:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")}");
                            },
                            OnSqlError = (sqlEx) =>
                            {
                                //sql執(zhí)行錯(cuò)誤后 日志記錄 (異步)
                                Console.WriteLine(sqlEx.Message.ToString());
                            },
                            OnTimeOut = (int timer) =>
                            {
                                //Console.WriteLine($"執(zhí)行SQL語(yǔ)句超過(guò)[{timer.ToString()}]毫秒...");
                            }
                        }
                    }
                    );

          //sqlclient.CodeFirst.InstallHisql();
          return sqlclient;
      }
  }

通過(guò)查詢庫(kù)存和訂單信息核對(duì)庫(kù)存是否扣減正常

select * from H_Stock 
select batch,sum(salesnum) as salesnum from H_Order group by batch
select orderid,sum(salesnum) as salesnum from H_Order group by orderid
select * from H_Order

核驗(yàn)結(jié)果

通過(guò)測(cè)試過(guò)程可以發(fā)現(xiàn) 不會(huì)產(chǎn)生死鎖也不會(huì)造成庫(kù)存扣減異常保證了數(shù)據(jù)的一致性

到此這篇關(guān)于基于C#解決庫(kù)存扣減及訂單創(chuàng)建時(shí)防止并發(fā)死鎖的問(wèn)題的文章就介紹到這了,更多相關(guān)c#庫(kù)存扣減防止并發(fā)死鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲

    C#實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • c#讀寫(xiě)注冊(cè)表示例分享

    c#讀寫(xiě)注冊(cè)表示例分享

    這篇文章主要介紹了c#讀寫(xiě)注冊(cè)表示例,示例中有詳細(xì)注釋,大家參考使用吧
    2014-01-01
  • C# 反射與 Quartz 實(shí)現(xiàn)流程處理詳情

    C# 反射與 Quartz 實(shí)現(xiàn)流程處理詳情

    根據(jù)要實(shí)現(xiàn)流程處理,比如用戶可以定義一個(gè)定時(shí)任務(wù),每周一查看報(bào)表。任務(wù)是用Quartz可實(shí)現(xiàn),但用戶自己選擇報(bào)表就比較麻煩,這時(shí)因?yàn)橄到y(tǒng)的不同模塊的生成報(bào)表的函數(shù)不同,這時(shí)便可以傳入一個(gè)方法名和方法的輸入?yún)?shù),就可以調(diào)用該方法。下面小編我為大家介紹具體過(guò)程
    2021-09-09
  • C# Winform實(shí)現(xiàn)波浪滾動(dòng)效果

    C# Winform實(shí)現(xiàn)波浪滾動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了C# Winform實(shí)現(xiàn)波浪滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • C#繪制中國(guó)象棋棋盤(pán)

    C#繪制中國(guó)象棋棋盤(pán)

    這篇文章主要為大家詳細(xì)介紹了C#繪制中國(guó)象棋棋盤(pán),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • C#中實(shí)現(xiàn)線程同步lock關(guān)鍵字的用法詳解

    C#中實(shí)現(xiàn)線程同步lock關(guān)鍵字的用法詳解

    實(shí)現(xiàn)線程同步的第一種方式是我們經(jīng)常使用的lock關(guān)鍵字,它將包圍的語(yǔ)句塊標(biāo)記為臨界區(qū),這樣一次只有一個(gè)線程進(jìn)入臨界區(qū)并執(zhí)行代碼,接下來(lái)通過(guò)本文給大家介紹C#中實(shí)現(xiàn)線程同步lock關(guān)鍵字的用法詳解,一起看看吧
    2016-07-07
  • C# WinForm打開(kāi)PDF文件并在窗體中顯示

    C# WinForm打開(kāi)PDF文件并在窗體中顯示

    本文主要介紹通過(guò)引用Adobe reader提供的COM組件,以實(shí)現(xiàn)在WinForm程序中顯示PDF文件的功能。
    2016-05-05
  • WPF實(shí)現(xiàn)手風(fēng)琴式輪播圖切換效果

    WPF實(shí)現(xiàn)手風(fēng)琴式輪播圖切換效果

    這篇文章主要為大家詳細(xì)介紹了WPF實(shí)現(xiàn)手風(fēng)琴式輪播圖切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • C#項(xiàng)目彩票選號(hào)實(shí)現(xiàn)思路

    C#項(xiàng)目彩票選號(hào)實(shí)現(xiàn)思路

    今天做了一個(gè)彩票選號(hào)的小軟件,將學(xué)到的知識(shí)點(diǎn)總結(jié)一下,下面通過(guò)本文給大家分享C#項(xiàng)目彩票選號(hào)實(shí)現(xiàn)思路,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • C#/.net程序調(diào)用Python的教程分享

    C#/.net程序調(diào)用Python的教程分享

    C#的優(yōu)勢(shì)在于window下的開(kāi)發(fā),不僅功能強(qiáng)大而且開(kāi)發(fā)周期短。而python則有眾多的第三方庫(kù),可以避免自己造輪子,利用C#來(lái)做界面,而具體實(shí)現(xiàn)使用python來(lái)實(shí)現(xiàn)可以大大提高開(kāi)發(fā)效率。本文介紹如何使用pythonnet來(lái)執(zhí)行python腳本,希望對(duì)大家有所幫助
    2023-03-03

最新評(píng)論

且末县| 肃宁县| 房山区| 南京市| 四会市| 抚松县| 连南| 东台市| 通山县| 慈利县| 新密市| 莒南县| 上蔡县| 奉新县| 桂东县| 延津县| 浙江省| 平遥县| 会宁县| 平陆县| 手游| 天气| 甘谷县| 乳山市| 大丰市| 仪征市| 巫山县| 南靖县| 宁海县| 泾源县| 德江县| 启东市| 工布江达县| 平安县| 台北市| 湖北省| 家居| 鹤壁市| 尼勒克县| 谢通门县| 来安县|