支持C#的分表分庫(kù)組件-Ctrip DAL
本文轉(zhuǎn)載自微信公眾號(hào)「后端Q」,作者conan。轉(zhuǎn)載本文請(qǐng)聯(lián)系后端Q公眾號(hào)。
簡(jiǎn)介
Ctrip DAL是攜程框架部開(kāi)發(fā)的數(shù)據(jù)庫(kù)訪問(wèn)框架,支持代碼生成和水平擴(kuò)展。其由攜程技術(shù)中心框架部DAL團(tuán)隊(duì)開(kāi)發(fā),歷經(jīng)3年不斷打磨,并在長(zhǎng)期的實(shí)際使用中基于大量的用戶反饋不斷優(yōu)化。
開(kāi)源范圍包括代碼生成器,Java客戶端和C#客戶端。
背景
隨著企業(yè)規(guī)模擴(kuò)張和業(yè)務(wù)量的急劇增加,作為系統(tǒng)核心的數(shù)據(jù)庫(kù)相關(guān)開(kāi)發(fā)也會(huì)經(jīng)歷一個(gè)由單一團(tuán)隊(duì)發(fā)展為多團(tuán)隊(duì);由單機(jī)擴(kuò)張到集群;由單數(shù)據(jù)庫(kù)發(fā)展為多數(shù)據(jù)庫(kù);由采用單一數(shù)據(jù)庫(kù)產(chǎn)品到多種數(shù)據(jù)庫(kù)產(chǎn)品并存的過(guò)程。伴隨這一過(guò)程的是如何管理數(shù)據(jù)庫(kù)擴(kuò)展,如何規(guī)范數(shù)據(jù)庫(kù)訪問(wèn),如何保護(hù)數(shù)據(jù)庫(kù)投資,如何應(yīng)對(duì)訪問(wèn)量增加,如何預(yù)防安全問(wèn)題等一系列挑戰(zhàn)。作為中國(guó)在線旅游行業(yè)的翹楚,攜程也曾經(jīng)面對(duì)同樣困擾。為了應(yīng)對(duì)這些挑戰(zhàn),實(shí)現(xiàn)企業(yè)10倍速發(fā)展,攜程開(kāi)發(fā)了具有自己特色的數(shù)據(jù)庫(kù)訪問(wèn)框架Ctrip DAL。
Ctrip DAL支持流行的分庫(kù)分表操作,支持Java和C#,支持Mysql和MS SqlServer。使用該框架可以在有效地保護(hù)企業(yè)已有數(shù)據(jù)庫(kù)投資的同時(shí),迅速,可靠的為企業(yè)提供數(shù)據(jù)庫(kù)訪問(wèn)層的橫向擴(kuò)展能力。整個(gè)框架包括代碼生成器和客戶端。工作模式是使用代碼生成器在線生成代碼和配置,通過(guò)DAL客戶端完成數(shù)據(jù)庫(kù)操作。生成器具有豐富的向?qū)е敢?,操作?jiǎn)單清晰,即可以批量生成標(biāo)準(zhǔn)DAO,也可以在方法級(jí)別定制數(shù)據(jù)庫(kù)訪問(wèn)??蛻舳藙t可以簡(jiǎn)單的通過(guò)標(biāo)準(zhǔn)的maven方式添加依賴。
Ctrip DAL與一般數(shù)據(jù)庫(kù)框架最大的不同是從企業(yè)跨部門(mén)的角度,統(tǒng)一管理數(shù)據(jù)庫(kù)相關(guān)資源。通過(guò)部署代碼生成器,企業(yè)可以做到有效的管理全公司的DAL開(kāi)發(fā)團(tuán)隊(duì),明確數(shù)據(jù)庫(kù)歸屬和定制數(shù)據(jù)庫(kù)訪問(wèn)。通過(guò)代碼生成器生成的標(biāo)準(zhǔn)DAO代碼與客戶端配合使用,可以大幅提高工作效率,保證代碼質(zhì)量。解決了業(yè)內(nèi)常見(jiàn)的伴隨業(yè)務(wù)成長(zhǎng)而帶來(lái)的系統(tǒng)維護(hù)困難,開(kāi)發(fā)效率低下,代碼風(fēng)格五花八門(mén),代碼質(zhì)量參差不齊等痛點(diǎn)問(wèn)題。
代碼生成器
代碼生成器允許用戶創(chuàng)建Dal團(tuán)隊(duì),組織開(kāi)發(fā)人員,管理數(shù)據(jù)庫(kù),創(chuàng)建DAO并生成代碼和配置。與一般基于JDBC driver的DB sharding產(chǎn)品不同的是,代碼生成器生成的代碼和配置可以直接拿來(lái)實(shí)用,完全無(wú)需用戶寫(xiě)一行代碼和配置。做到了只需開(kāi)發(fā)人員關(guān)心業(yè)務(wù)邏輯,而把繁瑣的數(shù)據(jù)庫(kù)相關(guān)的編碼和配置任務(wù)全部交給DAL。由于Ctrip DAL完全在DAO這層工作,也沒(méi)有什么這種SQL語(yǔ)句不支持,那種SQL語(yǔ)句不能用的情況。同時(shí)傳遞hints的方式也非常自然,每個(gè)方法都自帶hints的接口,需要DAL額外做什么可以直接按給定的已有名字來(lái)設(shè)置,無(wú)需改寫(xiě)原始的sql來(lái)添加怪異的注釋。
客戶端簡(jiǎn)介
客戶端配合代碼生成器生成的代碼來(lái)完成用戶的數(shù)據(jù)庫(kù)訪問(wèn)操作。通過(guò)Dev和QA兩方面雙重自動(dòng)化測(cè)試來(lái)保障質(zhì)量,覆蓋率達(dá)到99%,并經(jīng)過(guò)生產(chǎn)實(shí)際實(shí)用的的長(zhǎng)期嚴(yán)格檢驗(yàn)。為了適應(yīng)不同公司的實(shí)際情況,DAL客戶端定義了豐富的擴(kuò)展接口,覆蓋了從數(shù)據(jù)源管理,數(shù)據(jù)庫(kù)映射,連接串讀取到自定義訪問(wèn)方式等等方方面面的功能。同時(shí)為了方便系統(tǒng)監(jiān)控還內(nèi)置了系統(tǒng)狀態(tài),日志和統(tǒng)計(jì)模塊。
C#客戶端 API列表
以下這些API位于BaseDao類(lèi)中 方法族說(shuō)明:除了所示的方法之外,至少還包含一個(gè)帶有IDictionary hints參數(shù)的重載方法。
注意:增刪改均適用的API被歸類(lèi)至Update系列
- Create
- Object Insert<T>(T obj) where T : class, new() 方法族
- Object InsertByComplexPk<T>(T obj) where T : class, new() 方法族
- Boolean BulkInsert<T>(IList<T> list) where T : class, new() 方法族
- Retrieve
- IQuery<T> GetQuery<T>() where T : class, new()
- IList<T> GetAll<T>() where T : class, new() 方法族
- IList<T> SelectListOfSingleField<T>(String sql) 方法族
- IList<T> SelectList<T>(String sql) where T : class, new() 方法族
- IList<T> SelectList<T>(IQuery query) where T : class, new() 方法族
- IList<T> SelectListByAdapter<T>(String sql) where T : class, new() 方法族
- IList<T> SelectListByAdapter<T>(IQuery query) where T : class, new() 方法族
- IList<T> ExecListBySp<T>(String procName, StatementParameterCollection parameters) where T : class, new() 方法族
- T GetByKey<T>(Object key) where T : class, new() 方法族
- T SelectFirst<T>(String sql) where T : class, new() 方法族
- T SelectFirst<T>(IQuery query) where T : class, new() 方法族
- T VisitDataReader<T>(String sql, Func<IDataReader, T> callback) 方法族
- T VisitDataReaderBySp<T>(String procName, StatementParameterCollection parameters, Func<IDataReader, T> callback) 方法族
- DataTable SelectDataTable(String sql) 方法族
- DataTable ExecDataTableBySp(String procName, StatementParameterCollection parameters) 方法族
- DataSet SelectDataSet(String sql) 方法族
- DataSet SelectDataSet<T>(IQuery query) where T : class, new() 方法族
- DataSet ExecDataSetBySp(String procName, StatementParameterCollection parameters) 方法族
- IDataReader SelectDataReader(String sql) 方法族
- IDataReader ExecDataReaderBySp(String procName, StatementParameterCollection parameters) 方法族
- Object ExecScalar(String sql) 方法族
- Object ExecScalarBySp(String procName, StatementParameterCollection parameters) 方法族
- Update
- Int32 Update<T>(T obj) where T : class, new() 方法族
- IUpdatePartial<T> GetUpdatePartially<T>() where T : class, new()
- Int32 UpdatePartially<T>(IUpdatePartial<T> partially, T obj) where T : class, new() 方法族
- Int32 ExecNonQuery(String sql) 方法族
- void ExecSp(String procName, StatementParameterCollection parameters) 方法族
- Delete
- Int32 Delete<T>(T obj) where T : class, new() 方法族
https://github.com/ctripcorp/dal