怎么實現(xiàn)mybatis半自動化解耦!看看資深程序員怎么說

在JAVA發(fā)展過程中轧叽,涌現(xiàn)出一系列的ORM框架苗沧,JPA,Hibernate,Mybatis和Spring jdbc,本系列犹芹,將來研究Mybatis崎页。

通過研究mybatis源碼,可將mybatis的大致架構總結為下圖:

根據(jù)Mybatis源碼腰埂,將其抽象為三層:基礎支持層飒焦,核心處理層和接口層

基礎支持層包括:數(shù)據(jù)源、事務管理屿笼、日志牺荠、類型轉換、緩存驴一、Bind休雌、解析器等

核心處理層包括:配置解析、配置映射肝断、SQL解析杈曲、SQL執(zhí)行、結果集映射胸懈、插件等

接口層主要提供JAVA API

在本篇文章中担扑,將基于該框架圖,解決如下幾個問題:

Q1:結合代碼解析mybatis的CRUD原理是怎樣的趣钱?

Q2:為什么半自動化的Mybatis比自動化的Hibernate受歡迎涌献?

Q3:Mybatis為什么能實現(xiàn)松耦合?

一首有、mybatis的CRUD原理

小編分類整理了許多java進階學習材料和BAT面試題燕垃,需要資料的請加JAVA高階學習Q群:8515318105;就能領取2019年java架構師進階學習資料和BAT面試題井联。

為了解決該問題卜壕,我們先來看看如下代碼:

該代碼實現(xiàn)的功能是:根據(jù)user_id查詢用戶信息。 從代碼中烙常,我們可以看出印叁,大致分為:

讀取mybatis的全局配置文件mybatis-config.xml內(nèi)容

創(chuàng)建SqlSessionFactory會話工廠

根據(jù)SqlSessionFactory創(chuàng)建SQL會話SqlSession

執(zhí)行查詢操作

publicstaticvoidmain(String[]?args)throws?IOException{

//讀取配置文件內(nèi)容

String?resource?="demo/mybatis/resources/mybatis-config.xml";

InputStream?inputStream?=?Resources.getResourceAsStream(resource);

//創(chuàng)建SqlSessionFactory

SqlSessionFactory?sqlSF?=newSqlSessionFactoryBuilder().build(inputStream);

//創(chuàng)建SqlSession

SqlSession?sqlS?=?sqlSF.openSession();

//根據(jù)id查詢

try{

//查詢user_id=2的記錄

Listlist=?sqlS.selectList("getUserInfoById",2);

for(UserInfo?user?:list)?{

System.out.println("UserName:"+?user.getUser_name()?+",Addr:"+?user.getUser_addr());

}

}?finally?{

sqlS.close();

}

}

那么,我們再來看看军掂,Mybatis-config.xml內(nèi)容:

從內(nèi)容中,可以看出<configuration>下面有三個子節(jié)點,<properties>,<environment>和<mapper>節(jié)點昨悼。

那么蝗锥,這三個節(jié)點到底是表示什么呢?

1率触、properties節(jié)點表示屬性節(jié)點终议,可用于動態(tài)從外部獲取資源,將獲取的資源供上下文使用,我們來看看jdbc.properties內(nèi)容

#mysql

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://127.0.0.1:3306/db_test?characterEncoding=UTF-8

username=root

password=root

一看便知穴张,這是訪問數(shù)據(jù)庫相關參數(shù)细燎,那么哪個地方引用這些參數(shù)呢?<environment>子節(jié)點皂甘。

2玻驻、environment節(jié)點,環(huán)境節(jié)點配置節(jié)點偿枕,如用于配置數(shù)據(jù)庫測試環(huán)境璧瞬,開發(fā)環(huán)境等,很容易看出dataSource的相關子節(jié)點的占位符就引用了

properties節(jié)點從jdbc.properties獲取的內(nèi)容渐夸。

3嗤锉、mapper節(jié)點,即映射節(jié)點墓塌,用來鏈接映射文件瘟忱,我們來看看該映射文件內(nèi)容:

<?xml?version="1.0"?encoding="UTF-8"?>

PUBLIC?"-//mybatis.org//DTD?Mapper?3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--Query?all-->

SELECT?user_name?,user_addr?FROM?user_info

<!--Query?by?id-->

SELECT?user_name?,user_addr?FROM?user_info?WHERE?user_id=#{user_id}

<!--add-->

INSERT?INTO?user_info(user_name,user_addr)VALUES(#{user_name},#{user_addr})

<!--delete-->

DELETE?FROM?user_info?WHERE?user_id=#{user_id}

顯而易見,這就SQL的增刪改查苫幢。

通過如上分析访诱,我們在文章開始提出的三個問題,現(xiàn)在基本可以解決了态坦。

Q3:Mybatis為什么能實現(xiàn)松耦合?

從如上分析盐数,我們知道,使用mybatis作為ORM框架開發(fā)時伞梯,我們的SQL語句都寫在xml配置文件中(如上文的userInfo-config.xml)玫氢,從而解決了傳統(tǒng)硬編碼的強耦合問題,巧妙地實現(xiàn)了從“硬編碼”到“軟編碼”的過程谜诫。

除了松耦合的好處之外漾峡,有經(jīng)驗的開發(fā)人員應該清楚,硬編碼存在一個重大問題喻旷,即當改變SQL代碼后生逸,需要重新編譯、打包且预、部署等后槽袄,程序方可運行起來,而通過可配置化的xml方式實現(xiàn)的SQL語句锋谐,卻不需要遍尺。

Q4:為什么半自動化的Mybatis比自動化的Hibernate受歡迎?

從功能上講,Hibernate是非常強大的涮拗,但其有存在一些比較難以解決的問題:

學習成本大:對于新手乾戏,學習Hibernate的時間成本比Mybatis大很多迂苛,Mybatis很快就上手了

笨重:Hibernate強大的另一面,折射出其笨重的一面

封裝SQL:Hibernate封裝SQL鼓择,只向用戶提供API接口三幻,是造成其不靈活的根本因素

然而,mybatis卻將SQL獨立出來呐能,讓用戶自定義念搬。

通過如上對比,之所以說Hibernate自動化催跪,因為SQL生成锁蠕,解析,執(zhí)行等都是由Hibernate自動生成的懊蒸;

之所以說Mybatis半自動化荣倾,是因為SQL語句需要用戶自定義,SQL的解析骑丸,執(zhí)行等工作由Mybatis執(zhí)行舌仍。

可以這么說,傳統(tǒng)的jdbc是手工的通危,Hibernate是自動化的铸豁,而Mybati是基于jdbc和Hibernate的半自動化ORM框架。

二菊碟、完整Mybatis CRUD

小編分類整理了許多java進階學習材料和BAT面試題节芥,需要資料的請加JAVA高階學習Q群:8515318105;就能領取2019年java架構師進階學習資料和BAT面試題逆害。

創(chuàng)建Web Application項目

打開Intellij IDEA=>Create New Project=>Java Enterprise=>勾選 Web Application=>Next=>

給項目命名MybatisCRUD=>Finish

導入jar包

這里主要導入兩個jar包:MySQL驅動jar包和Mybatis jar包

Project Structure(Ctrl+Alt+Shift+S)=>Modules=>MybatisCRUD=>Dependencies=>選擇 JARS or directories…

成功導入后的結構如下:

創(chuàng)建測試數(shù)據(jù)

#創(chuàng)建數(shù)據(jù)庫

DROPDATABASEIFEXISTSdb_test

CREATEDATABASEdb_test

#創(chuàng)建數(shù)據(jù)表

DROPTABLEIFEXISTSUser_Info

CREATETABLEuser_info

(

user_idINT(5)?AUTO_INCREMENT?PRIMARYKEYNOTNULL,#用戶id

user_nameVARCHAR(50)NOTNULL,#用戶名

user_addrVARCHAR(100)NOTNULL#地址

)

#插入模擬數(shù)據(jù)

INSERTINTOuser_Info(user_name,user_addr)

VALUES('A','SH-PuDong'),('B','SH-YangPu'),

('C','SH-QingPu'),('D','SH-XuHui')

創(chuàng)建UserInfo實體

packagedemo.mybatis.entity;

publicclassUserInfo{

String?user_name;

String?user_addr;

publicStringgetUser_name(){

returnuser_name;

}

publicvoidsetUser_name(String?user_name){

this.user_name?=?user_name;

}

publicStringgetUser_addr(){

returnuser_addr;

}

publicvoidsetUser_addr(String?user_addr){

this.user_addr?=?user_addr;

}

}

創(chuàng)建三個資源文件

1.jdbc.property

#mysql

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://127.0.0.1:3306/db_test?characterEncoding=UTF-8

username=root

password=root

2.mybatis-config.xml

<?xml?version="1.0"?encoding="UTF-8"??>

PUBLIC?"-//mybatis.org//DTD?Config?3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--屬性-->

<!--環(huán)境-->

<!--映射-->

3.userInfo.config.xml

<?xml?version="1.0"?encoding="UTF-8"?>

PUBLIC?"-//mybatis.org//DTD?Mapper?3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--無條件查詢-->

SELECT?user_name?,user_addr?FROM?user_info

<!--通過id查詢-->

SELECT?user_name?,user_addr?FROM?user_info?WHERE?user_id=#{user_id}

<!--add-->

INSERT?INTO?user_info(user_name,user_addr)VALUES(#{user_name},#{user_addr})

<!--delete-->

DELETE?FROM?user_info?WHERE?user_id=#{user_id}

CRUD

1.查詢

packagedemo.mybatis.Test;

importdemo.mybatis.entity.UserInfo;

importorg.apache.ibatis.io.Resources;

importorg.apache.ibatis.session.SqlSession;

importorg.apache.ibatis.session.SqlSessionFactory;

importorg.apache.ibatis.session.SqlSessionFactoryBuilder;

importjava.io.IOException;

importjava.io.InputStream;

importjava.util.List;

publicclassTestMybatis{

publicstaticvoidmain(String[]?args)throwsIOException{

//讀取配置文件內(nèi)容

String?resource?="demo/mybatis/resources/mybatis-config.xml";

InputStream?inputStream?=?Resources.getResourceAsStream(resource);

//創(chuàng)建SqlSessionFactory

SqlSessionFactory?sqlSF?=newSqlSessionFactoryBuilder().build(inputStream);

//創(chuàng)建SqlSession

SqlSession?sqlS?=?sqlSF.openSession();

//根據(jù)id查詢

try{

//查詢user_id=2的記錄

List?list?=?sqlS.selectList("getUserInfoById",2);

for(UserInfo?user?:?list)?{

System.out.println("UserName:"+?user.getUser_name()?+",Addr:"+?user.getUser_addr());

}

}finally{

sqlS.close();

}

}

}

2.添加

packagedemo.mybatis.Test;

importdemo.mybatis.entity.UserInfo;

importorg.apache.ibatis.io.Resources;

importorg.apache.ibatis.session.SqlSession;

importorg.apache.ibatis.session.SqlSessionFactory;

importorg.apache.ibatis.session.SqlSessionFactoryBuilder;

importjava.io.IOException;

importjava.io.InputStream;

importjava.util.List;

publicclassTestMybatis{

publicstaticvoidmain(String[]?args)throwsIOException{

//讀取配置文件內(nèi)容

String?resource?="demo/mybatis/resources/mybatis-config.xml";

InputStream?inputStream?=?Resources.getResourceAsStream(resource);

//創(chuàng)建SqlSessionFactory

SqlSessionFactory?sqlSF?=newSqlSessionFactoryBuilder().build(inputStream);

//創(chuàng)建SqlSession

SqlSession?sqlS?=?sqlSF.openSession();

//添加數(shù)據(jù)

try{

UserInfo?addUser?=newUserInfo();

addUser.setUser_name("E");

addUser.setUser_addr("BJ-DongCheng");

sqlS.selectList("addUserInfo",addUser);

List?list=sqlS.selectList("listUserInfo");

for(UserInfo?user?:list){

System.out.println("UserName:"+user.getUser_name()+",Addr:"+user.getUser_addr());

}

}finally{

sqlS.close();

}

}

}

3.刪除

packagedemo.mybatis.Test;

importdemo.mybatis.entity.UserInfo;

importorg.apache.ibatis.io.Resources;

importorg.apache.ibatis.session.SqlSession;

importorg.apache.ibatis.session.SqlSessionFactory;

importorg.apache.ibatis.session.SqlSessionFactoryBuilder;

importjava.io.IOException;

importjava.io.InputStream;

importjava.util.List;

publicclassTestMybatis{

publicstaticvoidmain(String[]?args)throwsIOException{

//讀取配置文件內(nèi)容

String?resource?="demo/mybatis/resources/mybatis-config.xml";

InputStream?inputStream?=?Resources.getResourceAsStream(resource);

//創(chuàng)建SqlSessionFactory

SqlSessionFactory?sqlSF?=newSqlSessionFactoryBuilder().build(inputStream);

//創(chuàng)建SqlSession

SqlSession?sqlS?=?sqlSF.openSession();

//刪除

try{

sqlS.selectList("delUserInfoById",12);

List?list=sqlS.selectList("listUserInfo");

for(UserInfo?user?:list){

System.out.println("UserName:"+user.getUser_name()+",Addr:"+user.getUser_addr());

}

}finally{

sqlS.close();

}

}

}

代碼目錄結構

小編分類整理了許多java進階學習材料和BAT面試題空免,需要資料的請加JAVA高階學習Q群:8515318105吓歇;就能領取2019年java架構師進階學習資料和BAT面試題望艺。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偶妖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子纯陨,更是在濱河造成了極大的恐慌坛芽,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翼抠,死亡現(xiàn)場離奇詭異咙轩,居然都是意外死亡,警方通過查閱死者的電腦和手機阴颖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門活喊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人膘盖,你說我怎么就攤上這事胧弛。” “怎么了侠畔?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵结缚,是天一觀的道長。 經(jīng)常有香客問我软棺,道長红竭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任喘落,我火速辦了婚禮茵宪,結果婚禮上,老公的妹妹穿的比我還像新娘瘦棋。我一直安慰自己稀火,他們只是感情好,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布赌朋。 她就那樣靜靜地躺著凰狞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沛慢。 梳的紋絲不亂的頭發(fā)上赡若,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音团甲,去河邊找鬼逾冬。 笑死,一個胖子當著我的面吹牛躺苦,可吹牛的內(nèi)容都是我干的身腻。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼圾另,長吁一口氣:“原來是場噩夢啊……” “哼霸株!你這毒婦竟也來了?” 一聲冷哼從身側響起集乔,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤去件,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扰路,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尤溜,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年汗唱,在試婚紗的時候發(fā)現(xiàn)自己被綠了宫莱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡哩罪,死狀恐怖授霸,靈堂內(nèi)的尸體忽然破棺而出巡验,到底是詐尸還是另有隱情,我是刑警寧澤碘耳,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布显设,位于F島的核電站,受9級特大地震影響辛辨,放射性物質(zhì)發(fā)生泄漏捕捂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一斗搞、第九天 我趴在偏房一處隱蔽的房頂上張望指攒。 院中可真熱鬧,春花似錦僻焚、人聲如沸允悦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澡屡。三九已至,卻和暖如春咐旧,著一層夾襖步出監(jiān)牢的瞬間驶鹉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工铣墨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留室埋,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓姚淆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親屡律。 傳聞我的和親對象是個殘疾皇子腌逢,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

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