信也科技數據庫訪問中間件DAS揭祕

DAS簡介

DAS是信也科技自研的數據庫訪問中間件,是集數據庫管理,ORM,動態SQL構建和分庫分表支持的一體化關係型數據庫訪問解決方案。

看到這裏,你一定會說少年啊!已經有了那麼多ORM框架和分庫分表組件,像Hibernate,Mybatis,mycat,sharding jdbc,還有我們最愛的攜程DAL可供選擇,幹嘛還要重複造輪子?

答案很簡單,這些工具都不好用!而DAS是我們最新發明的高科技輪子。

警告!前方高能!非資深開發人員儘快撤離。請握緊鼠標,抓牢鍵盤!

DAS產品定位

你一定奇怪,既然要做數據庫中間件,爲什麼不像其他產品那樣,從JDBC或者數據庫協議層入手,在傳統數據庫上面做分庫分表或重新開發數據庫引擎?那樣多牛啊!現有程序不用改就可以無縫移植。爲什麼DAS還要提供ORM功能呢?

回答這個問題之前,讓我們先簡單回顧一下流行的數據庫編程過程。這有助於理解DAS的產品定位。

mybatis,Hibernate發明的年代還沒有什麼數據庫垂直與水平擴容,分庫分表之類的概念,自然也不會從設計上加以考慮。而現在隨便一個互聯網公司,每天產生的數據都是“天量”。因此一個正經的數據庫項目往往會同時用到ORM工具和分庫分表組件。無論是ORM還是分庫分表組件,一般都需要繁瑣的配置。區別只在於難度級別是受得了還是勸退。

以最流行的mybatis+任意分庫分表組件爲例,如果你是一個資深的CRUD boy,肯定非常熟悉下面的套路,在開始寫下圖中間最終實際的DAO代碼之前,你需要先搞定另外四件事情:

當你手忙腳亂搞好這些配置,第一次測試時候,十有八九不會成功,這個時候千萬不要氣餒,因爲更慘的還在後面,當在項目中使用獨立的ORM和分庫分表組件時,你會難過到流淚:

  • 見過在XML裏面寫代碼的嗎?mybatis 就是這樣以XML形式存放表結構和動態SQL語句,與實際調試用的Java代碼分離開,請告訴我如何在XML裏面debug?雖然mybatis的這種設計已經很過時了,但是它基於註解的新設計更挫,你見過上面足足十層奶油,底下卻只有一層蛋糕的奶油蛋糕嗎?mybatis的註解看上去就是這種感覺
  • 想增加一個新方法,得先改XML,再生成DAO Interface,最後才能使用,雖然儀式感滿滿,但編程效率奇低。或者你可嘗試在註解裏面寫SQL,也蠻爽的。
  • 分庫分表配置通常都比較複雜,而且基本上沒有自動化工具支持,全靠手配。這體驗跟矇眼徒手在一個裝滿圖釘的罈子裏捉泥鰍一樣刺激。我到現在還清楚的記得硬着頭皮看了3遍還看不懂某個分庫分表組件用戶手冊時的挫折感。
  • 最好的總在最後,你會發現不同環境的Datasource配置往往放在同一個項目中,通過profile或其他手段區分,很容易在打包階段出錯,而這個錯誤只有在部署階段的時候才能發現,排查時得先下載再解包,極其麻煩。更別提生產數據庫密碼泄露的安全隱患,而隨着庫,表的增長,做這些事情的痛苦指數從痛苦向無限痛苦飛速發展。如果你覺得這沒什麼,那你一定是能享受福報的那一批人。

當最終克服萬難代碼能工作時,你會發現跟總體的配置和代碼量相比,最終的DAO代碼只佔很少一部分。而就這一部分代碼裏面,真正有用的也只是極小一部分,不信你看:

public static void main(string[] args) throws IOException {    Inputstrean resourceAsstream Resources ogetResourceasstrean(“cc/sq1MupConfig.xml”);    sq1SessionFactory ssfenew sq1Session actoryBullder() .build(resourceAsstream);    ///mapper就是UserMapper接口的實現類

UserMapper mapper = sqlSession. getMapper(UserMapper.class);

User u = mapper.finduserById(10);

system.out.print1n();

}

上面這段典型的mybatis代碼。除了倒數第二行代碼,其他的都是什麼玩意?只是搶個兩分錢的紅包,幹嘛要“磕這麼多響頭”?刨去註釋和無關代碼,這裏面真正有用的代碼只佔1/5而已。你不覺得這個比例荒謬到可笑嗎?爲交付這一點點代碼,付出的代價如此之

“大”,是不是覺得哪裏不對?

其實要查詢,真正關鍵的信息就是數據庫名和查詢語句而已。評價一個設計的的好壞只要看實現一個需求在多大程度上只需要提供必要信息。額外步驟越多,設計越失敗!作爲參考,請思考餐廳用餐和自己買菜做飯的區別。

作爲一個老程序員,我已經厭倦了使用破爛工具。人嘛,要對自己好一點,誠實一點。一個人性化的數據庫訪問框架應該是這個樣子:

  • 具備簡潔明瞭的API,99%的操作都能一步搞定,使用起來如絲般順滑。

  • 使用面向應用,面向數據對象這種高級抽象,而不是鏈接,事務這類極易用錯的底層概念。

  • 提供基於Java的動態SQL生成器。在同一個上下文裏寫SQL和寫代碼,不用切來切去鏈接,事務之類的統統由框架搞定,不用操心資源的打開,關閉,泄露啥的,沒有使用就沒有傷害。

  • API既簡單又複雜。既能適應一般情況,又能處理特殊情況。別問,就要。

  • 內置分庫分表能力,不用再單獨集成第三方組件。分庫分表配置必須極簡單,連我都能學會,當然最好別學。如果你問一個研發人員這世界上什麼最痛苦?他一定會回答你學習新技術最痛苦。如果要再上一個檔次,那就是要學那種要花很多功夫學習卻會隔很長時間才用一兩次的技術,對,說的就是分庫分表配置這種。

  • 不要讓我手工編輯任何XML或配置文件,都已經2020年了,在幾萬塊的MAC上寫XML,就像參加豪華晚宴卻蹲在椅子上喫飯一樣,像什麼樣子。如果實在免不了要配置,那必須提供能配得上我一指禪的最好的編輯器。

  • 只用寫DAO相關代碼,其他一概不管。

於是2018年在時任CTO的規劃下,我們信也科技基礎組件團隊決定自己動手搞一套符合自己心意的數據庫訪問中間件,這就是

信也DAS

DAS是Database Access Service的縮寫。DAS的目標就是給研發人員提供一個一站式的數據庫訪問框架,讓研發人員用最簡單直接的方式開發數據庫訪問代碼,實現上面所有“非分”的想法。

爲實現這個目標,DAS提供:

  • 同時具備ORM和分庫分表能力的客戶端 DAS Client ;

  • 基於WEB頁面的數據庫配置管理和代碼生成工具 DAS Console ;

  • 可選的基於代理模式的 DAS Server。應用在直連和代理之間切換無需改代碼,也不用知道;

但DAS的真正的核心優勢不是這些組件,我們build了一個專業的團隊,7*24小時主動爲程序員服務,幫大家搞定從原子到宇宙尺度的任何數據庫問題。

在信也科技,研發人員發郵件告訴DAS團隊各個環境的數據庫配置和邏輯數據庫信息,DAS團隊通過DAS Console配置好並自動同步到公司的配置中心後,用戶只要在自己的項目裏面引入DAS Client的依賴就可以開始直接寫代碼。對,你沒有看錯,直接開始寫代碼,無需任何的本地配置工作。我們把中間件產品的研發從交付組件提升到交付服務的層面。

這,纔是我們成功的祕密![撒花]

DAS核心設計初探

你心中一定冷笑,吹吧你!那讓我們從技術角度看看 DAS的核心DAS Client 到底長什麼樣。

DAS Client的設計遵從分層抽象原則,從上到下分爲:

1. DAO層,一個完整的ORM框架。關於編程所有美好的想象都在這裏。

2. 分庫分表層。抽象數據庫操作差異,以統一的方式處理數據的路由與合併。

3. 執行層。操作底層數據庫完成實際工作,封裝數據源,鏈接與事務。

DAO層是程序員使用最頻繁的部分,今天會重點介紹這一部分,其他部分會在未來會逐一提供,請關注我們的“拍碼場”公衆號。

DAS ORM簡介:

DAS ORM的主要由預定義DAO類DasClient,SQL創建工具類SqlBuilder和特殊操作指令類Hints組成。下面一一介紹。

DasClient

DAS ORM的核心是DasClient類,來看看裏面提供了啥方法:

DasClient提供了幾乎所有常見的ORM操作,開箱即用,不需要用戶生成任何DAO接口或實現。

別跟我“扯犢子”,上代碼!

OK!猜猜看用DAS實現一個查詢操作需要幾行代碼?

Person pk = new Person();

pk.setName(“test”);

DasClient dao = DasClientFactory.getClient(“logicDbName”);

List plist = dao.queryBySample(pk);

客戶端創建到使用,兩行代碼完事,是不是很簡單粗暴?像我說的一樣,如果你要完成一個查詢,你需要提供就只是數據庫名和SQL,這裏SQL用sample data表示。除此以外,沒有多餘動作。沒有session,沒有事務,也沒有connection。只要寫的代碼足夠少,BUG就不會追上我。這就是傳說中的極簡編程風

通過這種預定義API的方式能節省多少代碼呢?再以一個實際例子對比一下完成同樣功能mybatis和DAS之間代碼量:

Mybatis mapping:

DAS對應代碼:

public List selectByExample(Strategyaccountdetail detail) throws SQLException {        return client.queryBySample(detail);

}

看到區別了嗎?在不需要寫一行XML的情況下,DAS用一行代碼就可以搞定 mybatis需要十幾行,甚至幾十行配置才能完成的功能。其實上面顯示的還只是完成這個功能完整mybatis配置的一小部分配置,不過已經足夠說明我並沒有吹牛

SqlBuilder

你一定會想,按樣例查詢這個例子還是非常容易提供通用實現的,如果要根據各種條件生成複雜,動態的SQL怎麼辦?是不是要寫很多if-else語句自己拼?圖樣!這時候就要SqlBuilder出馬了。還是讓我們看看實際的代碼對比: Mybatis mapping:

DAS對應代碼:

public List selectListByUserIdExample(Long userId, String strategyid, Integer typeId,

Date beginInserttime, Date endInserttime, Integer pageNum, Integer pageSize) throws SQLException {

SqlBuilder builder = SqlBuilder.selectAllFrom(definition).where().allOf(definition.Userid.eq(userId),definition.Isactive.eq(1),

definition.Strategyid.eq(strategyid).nullable(),

definition.Typeid.eq(typeId).nullable(),definition.Inserttime.greaterThanOrEqual(beginInserttime).nullable(),

definition.Inserttime.lessThanOrEqual(endInserttime).nullable()).

orderBy(definition.Inserttime.desc()).into(Strategyaccountdetail.class).offset(pageNum, pageSize).withLock();        return client.query(builder);

}

使用SqlBuilder的DAS的code是不是還是一樣緊緻光滑?有人會說最新的mybatis也有SqlBuiler嘛。那我們就也比一比,不要說我騙人: Mybatis Sql builder:

public string selectPersonLike(final String id, final String firstName, final string lastlame) 《

return new SQL() {

{

SELECT(“P. ID, P.USERNAIE, P.PASSHORD, P.FIRST _NANE, P.LAST NAME”);

FROM(“PERSON P”)                if (id != null) {

WHERE(“P.ID like#{id}”);

}                if (firstlame != null) {

WHERE(“P.FIRST MAE like #{firstliase}”);

}                if (lastlame != null) {

WHERE(“P.LAST NAMIE like #{lastName}”);

}                ORDER BY(“P.LAST. NAME”);

}

}.toString();

}

DAS SqlBuilder:

public SqlBuilder seletPersonLike(final string id, final String firstlane, final string lastName) {

Person.PersonDefinition P = Person.PERSON;        return sqlBuilder.selectAllFrom§ where().

allOf(

p.d.like(id).nullable(),

p.firstName.like(firstNane).nullable(),

p. lastNare .1ike(iastName).nullab1e()

).orderBy(p.lastName);

}

明顯還是DAS的SqlBuilder設計更出色!

Hints

一步到位的提供API會存在一個設計風險,那就是任何操作都會存在特殊情況。比如一個簡單的插入操作,就存在很多變體:

1. 在存在自增ID的情況下生成自增ID

2. 在存在自增ID的情況下使用自定義ID

3. 在存在自增ID的情況下生成自增ID並將生成的ID設置到輸入實體

4. 等等

普通的做法是爲每種特殊做法提供overload的方法,有幾種特殊情況就提供幾個方法。按照這種思路發展下去,方法的數量很快就會多到失控。如何才能確保在一個精簡的API集合上提供儘可能多的特殊操作呢?這就輪到Hints登場了。

你可能注意到DasClient的方法除了必要參數外,往往還會帶一個Hints。這個Hints要麼是以可變參數存在,要麼是作爲必要參數的一個屬性。DAS利用Hints傳遞特殊指令,幫助用戶處理靈活多變的場景。以插入單條記錄爲例,API長這樣:

public  int insert(T entity, Hints…hints) throws SQLException

調用的時候既可以只傳entity:

dao.insert§;

也可以傳最多一個hints

dao.insert(p, hints.insertWithId());

無論哪種情況,方法只有一個。 雖然Hints也算不上腦洞特別大的發明,但與ORM結合得如此之緊密自然,別無分號。這種設計帶來的便利是巨大的。不信可以參考一下如果用獨立的分庫分表組件會怎樣實現:

// Sharding database and table with using hintManager ,

String sql = “SELECT * FROM t order”;    try (HintManager hintManager = HintManager.getInstance(;

Connectlon conn = dataSource.getConnection();

PreparedStatement preparedstatement conn. prepareStatement(sq1)) {

hintManager.addDatabaseShardingValue(“t_order”, 1);

hintManager.addTableShardingValue(“t_order”, 2);        try (ResultSet rs = preparedStatement.executeQuery()) {            while (rs.next()) {                //…

}

}

}

上面需要3行獨立代碼完成的Hints相關工作。倒不是說這個分庫分表組件設計的不好。除了TiDB或Amazon Aurora這種真正的分佈式數據庫之外,絕大多數基於傳統數據庫之上的分庫分表組件都難以做到完全的對應用代碼透明。在特殊場景下都需要以某種方式傳遞特殊指令。如果依賴於現有ORM工具或基於JDBC,就會存在類似上面這種很不自然的代碼。

而DAS通過將Hints與ORM接口結合的方式,完美的解決了特殊與一般的矛盾。同樣的事情DAS只需要一行:

List<Person) plist = dao.query(selectAllFrom§. setHints(Hints.hints().shardValue(1).tableShardValue(2)));

在推廣過程中我們還發現一個有趣的事情。就是我們以爲用戶喜歡透明的分庫分表,但事實上,出於各種原因,用戶用的最多的反而是直接指定分庫分表。當然利用Hints可以很簡單的做到:

List plist = dao.query(selectAllFrom§.setHints(Hints.hints(). inShard(1).inTableShard(2)));

自研ORM還有一個額外的好處。那就是雖然從成本還有技術的方面來看,分庫分表技術目前還有市場,但長遠來看,這大概率是一種過渡性的技術。即使哪天人們完全解決了分佈式數據庫的性能和一致性問題,也還是需要某種面向應用的ORM技術來實現靈活多變的需求。這樣DAS就可以繼續發揮作用。從今天的標準來看,DAS ORM的設計在易用性和靈活性上已經達到了能達到的極限。

總結

DAS完美結合了ORM和分庫分表功能,其產品定位是進可攻,退可守。根據公司內部實際使用效果來看,使用DAS能極大提高研發效率,減少代碼量和出錯概率,再也沒有因配置導致的各種故障。

有一次偶爾路過聽到一個總監和下面tech leader的對話,總監問如果技術輸出,新的代碼裏面能否不用我們的DAS,leader微笑着但堅定的回答,不行,DAS很好用的,我要用。

對我們做框架的程序員來說,還有什麼比一句好用更高的評價嗎?

是好東西就要拿出來大家一起用,DAS已經開源,並提供了詳盡的文檔供大家參考,請大家盡情star~

GitHub地址:https://github.com/ppdaicorp/das

除了開源文檔,我們還提供在線技術支持,有興趣的朋友可以入羣獲得幫助或者更多活動信息。

最後說一句,不要重複造輪子是最廣爲人知的謬誤。你不造,只是把機會讓給別人。

歡迎入羣交流

作者介紹

赫傑輝,信也科技基礎組件部門主管、信也DAS產品負責人、佈道師。圖形化構建工具集x-series的作者。曾主持開發攜程開源數據庫訪問框架DAL。對應用開發效率提升和分佈式數據庫訪問機制擁有有多年研究積累。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章