MyBatis的跨數(shù)據(jù)庫能力

? ? ? ? ?最近項目組在驗證一個應(yīng)用場景精居,讓自己的應(yīng)用在MySQL和Oracle數(shù)據(jù)庫都能夠正常運行(你可以認(rèn)為我們沒事吃飽撐著玩)。首先感謝就是沒有用到存儲過程潜必,要不真的是要吐血了靴姿。其次使用MyBatis來做數(shù)據(jù)庫訪問的中間層,才能同時支持MySQL和Oracle刮便,即使如此空猜,這種同時支持也讓我們感到行大于知,做比想難恨旱。這種差異主要還是因為兩種數(shù)據(jù)庫的不同造成應(yīng)用SQL語句寫法上的差異辈毯,例如Oracle不允許寫雙引號的常量如where user_id="123",但是MySQL則是正常搜贤,為了兼容谆沃,我們需要使用單引號,下面我們把碰到的一些主要問題記錄下來仪芒,為了能存在自己的記憶中唁影。

1耕陷、關(guān)于日期類型的操作

? ? ? ?由于MySQL在插入yyyy-mm-dd HH:mm:ss格式的日期數(shù)據(jù)時候,對于映射的數(shù)據(jù)可以定義為String類型据沈,MySQL驅(qū)動會自動將字符串的日期數(shù)據(jù)轉(zhuǎn)換為MySQL的日期定義格式哟沫,但是Oracle則不允許將字符串?dāng)?shù)據(jù)直接映射為Oracle定義的日期列,必須通過SQL語句中使用to_date和to_char函數(shù)實現(xiàn)日期和字符的相互轉(zhuǎn)換锌介。這樣導(dǎo)致MyBatis中SQL寫法的不一致嗜诀。

? ? ? ?為了統(tǒng)一SQL寫法,對于映射為日期類型列的Java對應(yīng)數(shù)據(jù)需要定義為Date類型孔祸,這樣在MyBatis做參數(shù)映射Bind的時候隆敢,兩個數(shù)據(jù)庫的驅(qū)動都會支持Date類型的Java對象數(shù)據(jù)插入,從而避免了SQL語句的差別崔慧。至于將前端提交的日期字符串?dāng)?shù)據(jù)自動的映射到日期字段拂蝎,Spring的K/V映射對象需要擴(kuò)展Convert(String,Data)接口,對于JSON傳入的數(shù)據(jù)惶室,一般JSON解析器可以根據(jù)相關(guān)的Annotation注釋將字符串日期數(shù)據(jù)轉(zhuǎn)換為Date對象温自,這需要應(yīng)用底層支撐.例如fastjson在定義日期對象createDate上通過JSONField定義了日期轉(zhuǎn)字符串的默認(rèn)格式。

@JSONField(yyyy-MM-dd HH:mm:ss)

Date createDate; //創(chuàng)建時間

2皇钞、關(guān)于一次插入多記錄的操作

? ? ? ? ?MySQL能夠方便的將一個List<T>對象中的多條記錄通過一條SQL語句插入一張表捣作,提高了整個速度,這種插入和Java的Batch插入多條記錄不一致鹅士,是一次交互,一條語句搞定惩坑,只是Mysql默認(rèn)對一次交互的SQL語句長度有限制掉盅,默認(rèn)為1M,所以List中的記錄條數(shù)不能過多以舒,否則報錯 nested exception is com.mysql.jdbc.PacketTooBigException: Packet for query is too large (5677854 > 1048576).?You can change this value on the server by setting the max_allowed_packet' variable趾痘。

? ? ? ?另外一種場景,對于EXCEL導(dǎo)入這種業(yè)務(wù)蔓钟,如果所有記錄當(dāng)一個事務(wù)更新永票,我們會使用MyBatis的批量機(jī)制,類似如下滥沫,但是執(zhí)行的效率肯定沒有下面一條語句插入的速度快(見下面的foreach語法)侣集,尤其記錄數(shù)據(jù)到5000,10000條的時候,兩種處理方式的時間差會更加明顯兰绣。

SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);

? ? UserDao mapper = sqlSession.getMapper(UserDao.class);

? ? for (int i = 0; i < 500; i++) {

? ? ? ? user = new User();

? ? ? ? user.setId("test" + i);

? ? ? ? user.setName("name" + i);

? ? ? ? mapper.insert(user);

? ? }

? ? sqlSession.commit();

? ? ? ?由于兩個數(shù)據(jù)庫在處理這種多記錄插入語句的不同世分,我們可以充分利用MyBatis的databaseId這個屬性,通過if等表達(dá)式缀辩,在xml文件中臭埋,通過databaseId執(zhí)行不同的sql語句踪央,這可以作為跨數(shù)據(jù)庫通用的解決方案。注意這種批量插入的記錄數(shù)據(jù)的寫法瓢阴,記錄數(shù)不能過多畅蹂,避免超過單條SQL語句的長度,大家可以猜猜_databaseId這個屬性怎么配置來(度娘肯定知道)荣恐。

? ? ? ?對于我們而言液斜,需要明白MyBatis加載如下定義和上述定義的區(qū)別,下面的配置代表初始化過程會根據(jù)連接數(shù)據(jù)庫種類的不同募胃,優(yōu)先加載與該數(shù)據(jù)庫種類匹配的語句定義旗唁,在連接ORACLE數(shù)據(jù)的時候,將不加載此文件痹束。

3.關(guān)于數(shù)據(jù)庫翻頁記錄的操作

? ? ? ? ?這個應(yīng)該是兩最明顯的區(qū)別了检疫,很多人都知道MySql中分頁很簡單,因為它利用關(guān)鍵字limit來實現(xiàn)分頁查詢祷嘶;但是Oracle實現(xiàn)起來就比MySql要繁瑣得多了屎媳,在每個結(jié)果集中只有一個rownum字段標(biāo)明它的位置,并且只能用rownum<=某個數(shù)论巍,不能用rownum>=某個數(shù)烛谊,因為ROWNUM是偽列,在使用時所以需要為ROWNUM取一個別名嘉汰,變成邏輯列丹禀,然后來操作。例如:

select * from (select ROWNUM as num,A.* from (select * from testtable) A where ROWNUM<=40) where num >= 20;

? ? ? ? 由于兩個數(shù)據(jù)庫對于翻頁語句處理的不同鞋怀,雖然我們可以利用databaseId關(guān)鍵字寫出兩種不同的翻頁語句双泪,而且必然是兩條語句,一條查出符合條件的記錄總數(shù)密似,所以代碼實現(xiàn)會有一定的復(fù)雜和重復(fù)讀焙矛。所以更多的時候,應(yīng)用會擴(kuò)展MyBatis的插件Plugin機(jī)制残腌,對StamentHandler對象進(jìn)行攔截村斟,根據(jù)開發(fā)人員傳入的select語句,自動匹配數(shù)據(jù)庫的種類抛猫,完成翻頁記錄總數(shù)據(jù)的查詢蟆盹,這種機(jī)制根據(jù)傳入的select語句抽取,得出總的toatal記錄數(shù)邑滨,然后再自動組裝翻頁語句日缨,簡化了應(yīng)用開發(fā),只是查詢總數(shù)和封裝翻頁對象的過程交給了基礎(chǔ)組件掖看,也屏蔽了數(shù)據(jù)庫的差異匣距。

? ? ? ?以上幾種場景是目前我們在使用MyBatis跨平臺使用過程中碰到的問題面哥,在沒有實踐之前,總以為沒有存儲過程使用毅待,就可以很快在ORACLE和MySQL之間轉(zhuǎn)換尚卫,其實不然,還有較多細(xì)節(jié)需要關(guān)注尸红,底層框架也需要擴(kuò)展吱涉,尤其在翻頁交易場景中。其實在真正上線過程中外里,應(yīng)用可能還會擴(kuò)展Plugin機(jī)制怎爵,記錄超過指定執(zhí)行時間或者結(jié)果集的SQL語句,以協(xié)助應(yīng)用和數(shù)據(jù)庫之間發(fā)生問題時的場景分析盅蝗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鳖链,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子墩莫,更是在濱河造成了極大的恐慌芙委,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狂秦,死亡現(xiàn)場離奇詭異灌侣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)裂问,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門侧啼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人堪簿,你說我怎么就攤上這事慨菱。” “怎么了戴甩?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長闪彼。 經(jīng)常有香客問我甜孤,道長,這世上最難降的妖魔是什么畏腕? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任缴川,我火速辦了婚禮,結(jié)果婚禮上描馅,老公的妹妹穿的比我還像新娘把夸。我一直安慰自己,他們只是感情好铭污,可當(dāng)我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布恋日。 她就那樣靜靜地躺著膀篮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岂膳。 梳的紋絲不亂的頭發(fā)上誓竿,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機(jī)與錄音谈截,去河邊找鬼筷屡。 笑死,一個胖子當(dāng)著我的面吹牛簸喂,可吹牛的內(nèi)容都是我干的毙死。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼喻鳄,長吁一口氣:“原來是場噩夢啊……” “哼扼倘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起诽表,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤唉锌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后竿奏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袄简,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年泛啸,在試婚紗的時候發(fā)現(xiàn)自己被綠了绿语。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡候址,死狀恐怖吕粹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岗仑,我是刑警寧澤匹耕,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站荠雕,受9級特大地震影響稳其,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜炸卑,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一既鞠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盖文,春花似錦嘱蛋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽龄恋。三九已至,卻和暖如春桐玻,著一層夾襖步出監(jiān)牢的瞬間篙挽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工镊靴, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留铣卡,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓偏竟,卻偏偏與公主長得像煮落,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子踊谋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 9,709評論 0 44
  • (一) 我是在青旅認(rèn)識森森的殖蚕,當(dāng)時已經(jīng)是晚上11點轿衔,我躺在上鋪玩手機(jī),門從外頭被人推開睦疫,嘭的一聲巨響害驹,嚇得我手一抖...
    桃啃笙閱讀 729評論 6 12
  • 凌晨三點瓦糕,琴聲底洗、檀香縈繞在家里。 早上六點咕娄,廚房里的鍋碗瓢盆響聲亥揖,菜刀接觸砧板的咚咚聲,熱油烹炸鮮蔬的吱吱聲圣勒,聲音...
    魚教頭閱讀 374評論 1 1
  • 星期天徐块,我們?nèi)マr(nóng)家樂“大山鄰居”爬山。 在上山的途中灾而,我和媽媽發(fā)現(xiàn)路旁有的樹很特別,很多樹干上有很多疙...
    smile沐恩閱讀 380評論 1 2