Dapper操作SQL Server

平时使用dapper直接面向SQL比较多,这里做个总结。

环境基于.NET Core 3.1,开设2个程序同时做插入、更新等操作,以及理解事务的过程。

插入

数据库代码:

 

 public void Insert(string sql, object args)
        {
            try
            {
                using var connection = new SqlConnection(_connStr);
                if(connection.State == System.Data.ConnectionState.Closed) connection.Open();
                connection.Execute(sql, args);
            }catch(Exception ex)
            {
                throw ex;
            }
        }

 

测试所需的数据表与代码:

  

//插入数据
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            var baseDate = new DateTime(2022, 11, 17, 0, 0, 0, 0);
            Task.Factory.StartNew(() => {
                while (true)
                {
                    _manualResetEvent.WaitOne();
                    var msg = $"App1: {(DateTime.Now - baseDate).TotalMilliseconds}{Environment.NewLine}";
                    this.Dispatcher.Invoke(_handleLogMsg, msg);
                    var sqls = @"insert into KO_A(numbers) values(1);";
                    var args = new { DT = DateTime.Now };
                    try
                    {
                        new DBHelper().Insert(sqls, null);
                    }
                    catch (Exception ex)
                    {
                        this.Dispatcher.Invoke(_handleLogMsg, ex.Message);
                    }
                }
            });
        }
        ManualResetEvent _manualResetEvent = new ManualResetEvent(true);
        //暂停插入
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            _manualResetEvent.Reset();
        }

 

  APP2中的测试代码相同,同时执行一段时间后点击暂停。

测算UI发起时间到入库时间,为了方便统计,每行执行时间减去基准时间,算总的毫秒数。2应用下平均时间在200~300毫秒,

    

 

 多方读更数据

主要考虑实现幂等更新。这里,有2个app同时更新一张表的Numbers字段,每次更新伴随着version的叠加。version版本号的引入降低了:库存是否溢出的判断逻辑。

 数据表:

 

数据操作:

public int Update(string sql, object args)
        {
            int lines = -1;
            try
            {
                using var connection = new SqlConnection(_connStr);
                if (connection.State == System.Data.ConnectionState.Closed) connection.Open();
                using (var trans = connection.BeginTransaction())
                {
                    lines = connection.Execute(sql, args, trans);
                    //Thread.Sleep(1000);//延长模拟时间
                    trans.Commit();
                }
                return lines;  
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public IEnumerable<T> Get<T>(string sql, object args) where T : new()
        {
            try
            {
                using var connection = new SqlConnection(_connStr);
                if (connection.State == System.Data.ConnectionState.Closed) connection.Open();
                return connection.Query<T>(sql, args);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

 APP1和APP2的代码相同,只是在读取存货后,APP2会停顿0.2s再请求做更新,以验证幂等更新。

业务层代码:

public class KOBHandle
    {
        public KO_B Get()
        {
            var sqls = @"select * from KO_B;";
            var res = new DBHelper().Get<KO_B>(sqls, null).FirstOrDefault();
            return res;
        }
        public int Update(KO_B data)
        {
            var sqls = @"update KO_B set Numbers = @Num, version = version + 1 where version = @Ver;";
            return new DBHelper().Update(sqls, new { Num = data.Numbers, Ver = data.Version});
        }
    }

  

UI代码:

private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            var baseDate = new DateTime(2022, 11, 17, 0, 0, 0, 0);
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    _manualResetEvent.WaitOne();
                    try
                    {
                        Thread.Sleep(200);
                        var bl = new KOBHandle();
                        var res = bl.Get(); //UI获取的商品存货
                        if (res == null) return;
                        if (res.Numbers <= 0)
                        {
                            this.Dispatcher.Invoke(_handleLogMsg, "存库空.");
                            return;
                        }
                        var temp = res.Numbers;
                        var temp2 = new Random().Next(1, res.Numbers);
                        res.Numbers = res.Numbers -temp2;//随机出库若干
                        var rtn = new KOBHandle().Update(res);
                        var msg = $"App1: 存货:{temp}   出货:{temp2}    更新:{rtn}    {res.Version}{Environment.NewLine}";
                        this.Dispatcher.Invoke(_handleLogMsg, msg);
                    }
                    catch (Exception ex)
                    {
                        this.Dispatcher.Invoke(_handleLogMsg, ex.Message);
                    }
                }
            });
        }

rtn 1 表示更新成功,0表示未更新;

private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            var baseDate = new DateTime(2022,11,17,0,0,0,0);
            Task.Factory.StartNew(()=> {
                while (true)
                {
                    _manualResetEvent.WaitOne();
                    //Thread.Sleep(1000);
                    try
                    {
                        var bl = new KOBHandle();
                        var res = bl.Get(); //UI获取的商品存货
                        if (res == null) return;
                        if (res.Numbers <= 0)
                        {
                            this.Dispatcher.Invoke(_handleLogMsg, "存库空.");
                            return;
                        }
                        Thread.Sleep(200);//停顿200ms
                        var temp = res.Numbers;
                        var temp2 = new Random().Next(1, res.Numbers);
                        res.Numbers = res.Numbers - temp2;//随机出库若干
                        var rtn = new KOBHandle().Update(res);
                        var msg = $"App2: 存货:{temp}   出货:{temp2}    更新:{rtn}    {res.Version}{Environment.NewLine}";
                        this.Dispatcher.Invoke(_handleLogMsg, msg);
                    }
                    catch (Exception ex)
                    {
                        this.Dispatcher.Invoke(_handleLogMsg, ex.Message);
                    }
                }
            });
        }

测试结果:

 

 

1134为当前行数据版本号,存货3,APP1和APP2一致;APP1更新0表示失败,APP2更新1表示更新成功。

同理分析1136,APP1更新成功;APP2更新不成功。

 

posted on 2022-11-17 14:32  益而不损  阅读(395)  评论(0)    收藏  举报