前言 上一篇介紹了擴展類庫的功能簡介,通過json文件配置sql語句 和 sql語句的直接執行,這篇開始說明sql配置的策略模塊:策略管理器與各種策略的配置。 類庫源碼:github:https://github.com/skigs/EFCoreExtend 引用類庫:nuget:https://w ...
前言
上一篇介紹了擴展類庫的功能簡介,通過json文件配置sql語句 和 sql語句的直接執行,這篇開始說明sql配置的策略模塊:策略管理器與各種策略的配置。
類庫源碼:github:https://github.com/skigs/EFCoreExtend
引用類庫:nuget:https://www.nuget.org/packages/EFCoreExtend/
PM> Install-Package EFCoreExtend
策略管理器功能簡介
用於管理策略 與 策略執行器和調用(目前分為三種策略執行器),目的為了讓配置的sql語句更加簡單、自動化等等。
1) 策略類型管理
a) 管理各種策略類型,用於初始化配置文件中的策略配置轉換成對象
2) 策略對象配置
a) 通過 sql配置的執行器 的形參傳遞策略對象
b) 通過 配置文件(分為表和sql) 配置策略對象
c) 配置到 全局策略 中(策略管理器中)
d) 策略對象獲取的優先順序:通過執行器的形參傳遞的策略對象 > sql配置的策略對象 > 表配置的策略對象 > 全局策略中配置
3) 策略執行器(一般通過策略對象進行相應的處理)
a) 初始化型的策略執行器:這種類型的會在第一次調用GetExecutor的時候執行,只會執行一次,除非sql配置有改動
- 配置策略對象的初始化、替換表名、合併分部sql等的策略執行器
b) sql執行前的策略執行器:一般用於對SqlParameter進行解析到sql中
- foreach策略執行器:對SqlParameter或者某些數據類型(list/dictionary/model)進行遍歷生成字串替換到sql中
c) sql執行時的策略執行器:一般用於緩存和日誌記錄
- sql與參數的日誌記錄策略執行器
- 查詢緩存與清理策略執行器
表名替換策略
通過特定的標簽代替表名在sql配置中呈現(該策略對象預設已經添加到全局策略中,因此並不一定要在配置文件中配置):
{ "policies": { //表配置的策略對象(會包含到表下的所有sql配置中) //表名策略 "tname": { //"tag": "##tname" //預設值為 ##tname } }, "sqls": { "GetList": { "sql": "select * from ##tableName where name=@name", // => select * from [Person] where name=@name "type": "query", "policies": { //sql配置的策略對象 //表名策略 "tname": { "tag": "##tableName", //預設值為 ##tname "prefix": "[", //首碼 "suffix": "]" //尾碼 } } } } }
配置初始化:
1 public static void Init() 2 { 3 //載入配置 4 EFHelper.Services.SqlConfigMgr.Config.LoadDirectory(Directory.GetCurrentDirectory() + "/Datas"); 5 6 //設置到全局策略中(一般用於設置 初始化型的策略對象),將策略對象設置到全局之後,會包含到所有配置中的 7 EFHelper.Services.SqlConfigMgr.PolicyMgr.SetGlobalPolicy( 8 //TableNamePolicy對象預設已經添加到全局策略中 9 new TableNamePolicy //表名策略在配置文件中呈現的key:tname(可以通過SqlConfigConst.TableNamePolicyName獲取) 10 { 11 Tag = "##tname", 12 }); 13 }
配置執行器調用:
1 public IReadOnlyList<Person> GetList() 2 { 3 tinfo = db.GetConfigTable<Person>(); 4 return tinfo.GetExecutor().QueryUseModel<Person>(new 5 { 6 name = "tom" 7 }, null, null, 8 //通過參數傳遞策略對象(一般用於設置 sql執行前 或 執行時的策略對象, 9 // 而初始化型的一般在配置文件或全局策略中設置) 10 new[] { new SqlL2QueryCachePolicy() }); 11 }
說明:
策略對象獲取的優先順序(如果策略對象設置到多個地方了): 執行器形參傳遞的策略對象 > sql配置的策略對象 > 表配置的策略對象 > 全局策略中配置
分部sql策略
分部sql目的為了將sql分部在不同的配置中,以便sql的可重用:
Person.json配置:
{ "sqls": { "GetListSection": { "sql": "select * from ##tname where #{WhereSec}", //最終生成的sql:select * from Person where name=@name or addrid in (select id from Address where id=@addrid) "type": "query", "policies": { //分部sql策略,以便將sql分部在不同的配置中(註意:分部策略是對sql的分部,可以在分部sql下再進行分部sql(子分部),但是不會繼承分部sql中的policies(策略對象)等的配置) "section": { //"tagPrefix": "#{", //策略首碼標記符,預設為 #{ //"tagSuffix": "}", //策略尾碼標記符,預設為 } "sqlNames": [ "WhereSec" ] //指定sql的名稱(同表下的SqlName) //"tableSqlNames": { //指定其他表的sql名稱(key為TableName,value為SqlName) //} } } }, "WhereSec": { "sql": " #{WhereSec1} or addrid in (#{Address.ListSec}) ", "type": "nonexecute", //不用於執行的sql類型 "policies": { "section": { "sqlNames": [ "WhereSec1" ], "tableSqlNames": { //指定其他表的sql名稱(key為TableName,value為SqlName) "Address": "ListSec" } } } }, "WhereSec1": { "sql": "name=@name", "type": "nonexecute" } } }
Address.json:
{ "sqls": { "ListSec": { "sql": "select id from ##tname where #{WhereSec}", "type": "nonexecute", "policies": { "section": { "sqlNames": [ "WhereSec" ] //指定sql的名稱(同表下的SqlName) } } }, "WhereSec": { "sql": "id=@addrid", "type": "nonexecute" } } }View Code
配置執行器調用:
1 public IReadOnlyList<Person> GetListSection() 2 { 3 tinfo = db.GetConfigTable<Person>(); 4 return tinfo.GetExecutor().QueryUseModel<Person>(new 5 { 6 name = name, 7 addrid = 123, 8 }); 9 }View Code
查詢緩存與緩存清理策略
查詢緩存分為 一級緩存 和 二級緩存。
一級查詢緩存策略
一級緩存僅作用於SqlConfigExecutor對象中,而且不能設置緩存過期時間。
配置:
{ "sqls": { "GetListL1Cache": { "sql": "select * from ##tname where name=@name", "type": "query", "policies": { "l1cache": {} //一級查詢緩存,僅作用於SqlConfigExecutor對象 } } } }View Code
配置執行器調用:
public void GetListL1Cache() { var tinfo = db.GetConfigTable<Person>(); var exc = tinfo.GetExecutor(); var q1 = exc.QueryUseModel<Person>(new { name = _name }); var q2 = exc.QueryUseModel<Person>(new { name = _name }); //一級緩存作用於SqlConfigExecutor,那麼同一個SqlConfigExecutor對象下, // 相同的sql和SqlParameter獲取的數據是一樣的 Assert.True(q1 == q2); var q3 = exc.QueryUseModel<Person>(new { name = _name + "1" }); //參數變了 Assert.True(q1 != q3); }View Code
二級查詢緩存策略
二級查詢緩存,作用於整個程式運行期間,也可配置到Redis中,如果同時配置了二級緩存和一級緩存預設是使用二級緩存(策略執行器的優先順序有關)。
配置:
{ "name": "Person", "policies": { //二級查詢緩存,作用於整個程式運行期間 / 或者跨進程分散式(Redis),如果同時配置了二級緩存和一級緩存預設時使用二級緩存(策略執行器的優先順序有關) "l2cache": { //"type":"", //緩存的類型(Query預設為:query, Scalar預設為:scalar) "expiry": { //註意如果沒有設置expiry的date/span,那麼緩存不會過期的 //"date": "2018-01-01", //指定緩存的過期日期 //"span": "00:00:03" //指定緩存的過期間隔(換算日期為:當前時間 + 時間間隔) //"isUpdateEach": true //是否每次獲取緩存之後更新過期時間(這個屬性 + span屬性來進行模擬session訪問更新過期時間) } } }, "sqls": { "CountL2Cache": { "sql": "select count(*) from ##tname", "type": "scalar", "policies": { "l2cache": { "expiry": { "span": "00:00:03", //指定緩存的過期間隔,這裡設置為3秒 "isUpdateEach": true //每次獲取緩存之後更新過期時間 } } } } } }
配置執行器調用:
public int CountL2Cache(TimeSpan? span = null) { var tinfo = db.GetConfigTable<Person>(); if (span.HasValue) { return (int)tinfo.GetExecutor().ScalarUseModel(null, null, //通過形參傳遞緩存策略對象:更改為不自動更新時間的 new SqlL2QueryCachePolicy { Expiry = new QueryCacheExpiryPolicy(span.Value, false) }); } else { return (int)tinfo.GetExecutor().Scalar(); } }View Code
更多的配置說明:
{ "name": "Person", "sqls": { "GetListL2Cache": { "sql": "select * from ##tname", "type": "query", "policies": { "l2cache": { //二級查詢緩存,不設置緩存過期時間(緩存不過期) } } }, "GetListL2Cache1": { "sql": "select * from ##tname", "type": "query", "policies": { "l2cache": { "type": "query1" //指定CacheType,預設為query } } }, "GetListL2Cache2": { "sql": "select * from ##tname where 2=2", "type": "query", "policies": { "l2cache": { "expiry": { "date": "2018-01-01" //指定緩存的過期日期 } } } }, "GetListL2Cache3": { "sql": "select * from ##tname where 3=3", "type": "query", "policies": { "l2cache": { "expiry": { "span": "00:00:03" //指定緩存的過期間隔(換算日期為:當前時間 + 時間間隔),為了方便測試因此這裡指定了3秒 } } } }, "CountL2Cache": { "sql": "select count(*) from ##tname", "type": "scalar", "policies": { "l2cache": { "expiry": { "span": "00:00:03", //指定緩存的過期間隔(換算日期為:當前時間 + 時間間隔),為了方便測試因此這裡指定了3秒 "isUpdateEach": true //是否每次獲取緩存之後更新過期時間(這個屬性 + span屬性來進行模擬session訪問更新過期時間) } } } } } }View Code
二級緩存清理策略
配置:
{ "policies": { //二級查詢緩存清理策略 "clear": { "isAsync": true,//是否非同步進行清理 "isSelfAll": true, //是否清理 所在表下 的所有緩存 "tables": [ "Address" ], //需要進行緩存清理的表的名稱(一般用於清理 其他表下 的所有查詢緩存) "cacheTypes": [ "query", "scalar1" ], //需要進行緩存清理的類型(用於清理 所在表下 的CacheType查詢緩存) "tableCacheTypes": { //需要進行緩存清理的類型(key為TableName,value為CacheType,一般用於清理 其他表下 的CacheType) "Address": "query" } } }, "sqls": { "CountL2Cache": { "sql": "select count(*) from ##tname", "type": "scalar", "policies": { "l2cache": { "type": "scalar1", //緩存的類型(Query預設為:query, Scalar預設為:scalar) "expiry": { "span": "00:00:03" } } } }, "AddPersonL2Cache": { "sql": "insert into ##tname(name, birthday, addrid) values('tom_t2cache', '2018-1-1', 123) ", "type": "nonquery", "policies": { "clear": { "isSelfAll": true //是否清理 所在表下 的所有緩存 } } } } }View Code
配置執行器調用:
1 public class PersonBLL 2 { 3 DBConfigTable tinfo; 4 public PersonBLL(DbContext db) 5 { 6 tinfo = db.GetConfigTable<Person>(); 7 } 8 9 public int CountL2Cache() 10 { 11 return (int)tinfo.GetExecutor().Scalar(); 12 } 13 14 public int AddPersonL2Cache() 15 { 16 return tinfo.GetExecutor().NonQuery(); 17 } 18 }View Code