[轉]Dapper的正確使用姿式

(轉載請刪除括號裏的內容)javascript

本文demo適用於MySQL

Dapper優點和缺點

優勢

高性能、易排查、易運維、靈活可控html

缺點

和EF相比,手寫sql當修改表結構不易發現bug。
習慣了EF後再來使用Dapper,會很難適應那種沒有了強類型的安全感。不過能夠用單元測和心細來避免。java

數據庫鏈接

問題:IDbConnection需不須要手動Open打開鏈接
答案:有時候須要有時候不須要mysql

Dapper鏈接可分兩種:主動管理(本身管理鏈接的打開和關閉)和自動管理(自動管理鏈接的打開和關閉)git

//短短三行代碼即實現了dapper鏈接的主動管理和自動管理bool wasClosed = cnn.State == ConnectionState.Closed;//判斷鏈接是否爲關閉狀態...if (wasClosed) cnn.Open();...if (wasClosed) cnn.Close();

源碼位置 https://github.com/StackExchange/Dapper/blob/master/Dapper/SqlMapper.cs#L530github

Note:ADO.NET默認是啓用鏈接池的 Pooling = true,鏈接池中最大鏈接數,默認爲100web

在使用Dapper的過程當中,你有可能遇到過鏈接池超過最大限制。那問題是怎麼來的呢?
若是主動管理或者自動管理鏈接都不會有問題。就怕你管理一半,打開不關閉:sql

//循環執行兩百次左右就能夠重現鏈接池超過最大限制DBContext dBContext2 = new DBContext();dBContext2.DbConnection.Open();

解決辦法相信不用我說了。docker

Note:在使用事務的時候須要手動打開鏈接,請不要忘記在finally裏面Close。

增刪改查的優化

批量新增

//一、可經過匿名對象集合進行參數化數據新增。(性能優化參考3)DbConnection.Execute(sqlStr, ListEntity);//二、【sql拼接可大大優化執行效率】在values後面帶上多有要插入的值。(若是數據太大可分批插入,如1000條一提交)insert into tt (a,b,c,d) values (50,1,'1','1'), (51,2,'1','2'); //三、參數化防sql注入var sql = insert into tt (a,b,c,d) values (@a1,@b1,@c1,@d1), (@a2,@b2,@c2,@d2); DynamicParameters dynamicParameters = new DynamicParameters();dynamicParameters.Add("a1","value");dynamicParameters.Add("b1","value");dynamicParameters.Add("c1","value");dynamicParameters.Add("a2","value");dynamicParameters.Add("b2","value");dynamicParameters.Add("c2","value");dynamicParameters.Add("d2","value");DbConnection.ExecuteScalar<int>(sql, dynamicParameters)

批量修改

//1、可經過匿名對象集合進行參數化數據修改。(須要修改的值都不同的狀況下,性能優化參考4)DbConnection.Execute(sqlStr, ListEntity);//2、若是須要修改的值都是同樣,只是條件不同。(使用SQL語句中的IN語法)DbConnection.Execute("UPDATE tt SET aa = @aa where bb in @bb;", new { aa, bb }); //3、快速批量修改(此方法很是適合`新增或修改`數據的場景,可經過建聯合惟一索引來實現新增或修改的區分。【組合字段不能爲空,不然爲空 不作惟一,有重複空數據】)insert into test_tbl (id,dr) values (1,'2'),(2,'3'),...(x,'y') on duplicate key update dr=values(dr);//4、參數化防sql注入var sql = insert into test_tbl (id,dr) values (@id1,@dr1),(@id2,@dr2),...(@idn,@drn) on duplicate key update dr=values(dr);DynamicParameters dynamicParameters = new DynamicParameters();dynamicParameters.Add("id1","value");dynamicParameters.Add("dr1","value");dynamicParameters.Add("id2","value");dynamicParameters.Add("dr2","value");...dynamicParameters.Add("idn","value");dynamicParameters.Add("drn","value");DbConnection.ExecuteScalar<int>(sql, dynamicParameters)

批量刪除

同理,也可使用參數化和IN語法數據庫

查詢第一條數據

dBContext.DbConnection.QueryFirstOrDefault<ItemFCLPO>("SELECT * from itemfcl_temp limit 1;");    //正確dBContext.DbConnection.QueryFirstOrDefault<ItemFCLPO>("SELECT * from itemfcl_temp;");            //錯誤dBContext.DbConnection.Query<ItemFCLPO>("SELECT * from itemfcl_temp;").FirstOrDefault();         //錯誤dBContext.DbConnection.Query<ItemFCLPO>("SELECT * from itemfcl_temp;").ToList().FirstOrDefault();//錯誤

If擴展方法

使用過Mybatis的同窗都知道,在xml裏面寫if、else仍是蠻好用的。雖然我仍是不喜歡在xml裏面寫sql。
那麼在Dapper裏面是否是也能簡便操做,答案是確定的。這就得慶幸C#牛逼的語法了。

public static class StringExtension{    public static string If(this string str, bool condition) {        return condition ? str : string.Empty;    }}

而後咱們的sql就能夠這樣拼接了

left join MaintenanceTemplates it on it.Id = m.MaintenanceTemplateIdwhere m.IsDeleted = 0{" and m.Code = @KeyWord ".If(!string.IsNullOrWhiteSpace(input.KeyWord))}{" and m.ProjectId = @ProjectId ".If(input.ProjectId.HasValue)}{" and a.ProductId = @ProductId ".If(input.ProductId.HasValue)}

比起之前又臭又長的if判斷,我的感受好多了。

Note:Dapper不會由於傳多了參數而報錯,因此放心使用If

工做單元

使用EF的時候很方便作事務處理,而在Dapper中貌似就沒那麼優雅了。
咱們每次在事務邏輯開始前都須要BeginTransaction開啓,事務結束後都須要CommitTransaction提交。代碼看起來也就稍顯混亂。
若是咱們經過特性標記的方式,在標記了UnitOfWork特性的方法自動開啓和提交事務那就完美了。以下:

[UnitOfWork]public virtual void Test(){    //執行業務邏輯}

固然,這是可行的。經過AOP攔截,在方法執行前開啓事務,在方法執行後提交事務就能夠了。
實現以下:
須要Nuget包Autofac.Extensions.DependencyInjection Autofac.Extras.DynamicProxy

[UnitOfWork]public virtual void DelUser(){    var sql = "select * from UserTemp";    var userList = dBContext.DbConnection.Query<object>(sql);    var sql2 = $@"INSERT into UserTemp VALUES(0,'{DateTime.Now.ToString()}','sql2執行成功')";    dBContext.DbConnection.Execute(sql2);    throw new Exception("主動報錯");//驗證事務 是否有效    var sq3 = $@"INSERT into UserTemp VALUES(0,'{DateTime.Now.ToString()}','sq3執行成功')";    dBContext.DbConnection.Execute(sq3);}
public class UnitOfWorkIInterceptor : IInterceptor{    private DBContext dBContext;    public UnitOfWorkIInterceptor(DBContext dBContext) {        this.dBContext = dBContext;    }    public void Intercept(IInvocation invocation) {        MethodInfo methodInfo = invocation.MethodInvocationTarget;        if (methodInfo == null)            methodInfo = invocation.Method;        UnitOfWorkAttribute transaction = methodInfo.GetCustomAttributes<UnitOfWorkAttribute>(true).FirstOrDefault();        //若是標記了 [UnitOfWork],而且不在事務嵌套中。        if (transaction != null && dBContext.Committed)        {            //開啓事務            dBContext.BeginTransaction();            try            {                //事務包裹 查詢語句                 //https://github.com/mysql-net/MySqlConnector/issues/405                invocation.Proceed();                //提交事務                dBContext.CommitTransaction();            }            catch (Exception ex)            {                //回滾                dBContext.RollBackTransaction();                throw;            }        }        else        {            //若是沒有標記[UnitOfWork],直接執行方法            invocation.Proceed();        }    }}

完整的測試源碼,會在文末提供。

SQL監控

使用EF的同窗應該不少人都知道MiniProfiler,我在前些年分享EF的時候有作過簡單介紹。
那麼咱們在執行Dapper的時候是否是也能夠對生成的sql作檢測和性能監控。
答案是確定的。Git地址

MiniProfiler監控套件還真不是通常的強。EF、MongoDB、MySql、Redis、SqlServer通通支持。
接下來咱們實現對Dapper監控,導入Nuget包MiniProfiler.AspNetCore

public class ActionFilter : IAsyncActionFilter{    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) {        var profiler = MiniProfiler.StartNew("StartNew");        using (profiler.Step("Level1"))        {            //執行Action            await next();        }        WriteLog(profiler);    }    /// <summary>    /// sql跟蹤    /// 下載:MiniProfiler.AspNetCore    /// </summary>    /// <param name="profiler"></param>    private void WriteLog(MiniProfiler profiler) {        if (profiler?.Root != null)        {            var root = profiler.Root;            if (root.HasChildren)            {                root.Children.ForEach(chil =>                {                    if (chil.CustomTimings?.Count > 0)                    {                        foreach (var customTiming in chil.CustomTimings)                        {                            var all_sql = new List<string>();                            var err_sql = new List<string>();                            var all_log = new List<string>();                            int i = 1;                            customTiming.Value?.ForEach(value =>                            {                                if (value.ExecuteType != "OpenAsync")                                    all_sql.Add(value.CommandString);                                if (value.Errored)                                    err_sql.Add(value.CommandString);                                var log = $@"【{customTiming.Key}{i++}{value.CommandString} Execute time :{value.DurationMilliseconds} ms,Start offset :{value.StartMilliseconds} ms,Errored :{value.Errored}";                                all_log.Add(log);                            });                            //TODO 日誌記錄                            //if (err_sql.Any())                            // Logger.Error(new Exception("sql異常"), "異常sql:\r\n" + string.Join("\r\n", err_sql), sql: string.Join("\r\n\r\n", err_sql));                            //Logger.Debug(string.Join("\r\n", all_log), sql: string.Join("\r\n\r\n", all_sql));                        }                    }                });            }        }    }}

運行效果:

Demo源碼

完整的Demo源碼:https://github.com/zhaopeiym/BlogDemoCode/tree/master/Dapper_Demo/DapperDemo

結束

最後給你們推薦一個開源項目quartzuihttps://github.com/zhaopeiym/quartzui
基於Quartz.NET 3.0的web管理界面,開箱即用。也能夠完美運行在樹莓派上。

docker run -v /fileData/quartzuifile:/app/File  --restart=unless-stopped --privileged=true --name quartzui -dp 5088:80 bennyzhao/quartzui:RaspberryPi

運行在普通PC或雲主機上

docker run -v /fileData/quartzuifile:/app/File  --restart=unless-stopped --privileged=true --name quartzui -dp 5088:80 bennyzhao/quartzui

新建QQ羣工控物聯:995475200


---------------------
做者:農碼一輩子
來源:CNBLOGS
原文:https://www.cnblogs.com/zhaopei/archive/2019/05/20/dapper.html
版權聲明:本文爲做者原創文章,轉載請附上博文連接!
內容解析By:CSDN,CNBLOG博客文章一鍵轉載插件

相關文章
相關標籤/搜索