Mybatis(1):簡(jiǎn)單案例入門(mén)及總結(jié)

????之前在面試工作的時(shí)候,我當(dāng)時(shí)用的是hibernate,但是現(xiàn)在互聯(lián)網(wǎng)項(xiàng)目并發(fā)量大,一般都會(huì)選擇使用Mybatis,于是自己把Mybatis學(xué)習(xí)了,因?yàn)橹坝衕ibernate的底子,相比較hibernate簡(jiǎn)單的多,但是對(duì)sql編寫(xiě)的能力要求高。在使用起來(lái)各有各的好處吧,在下面的筆記中,我也寫(xiě)了一些關(guān)于他們兩者的區(qū)別。個(gè)人建議如果有時(shí)間的話,把hibernate和Mybatis都學(xué)習(xí)一下,這樣對(duì)你的幫助也許會(huì)更大。


1.Mybatis的簡(jiǎn)單介紹

MyBatis 本是apache的一個(gè)開(kāi)源項(xiàng)目iBatis, 2010年這個(gè)項(xiàng)目由apache software foundation遷移到了google code,并且改名為MyBatis 。2013年11月遷移到Github。??? MyBatis是一個(gè)優(yōu)秀的持久層框架,它對(duì)jdbc的操作數(shù)據(jù)庫(kù)的過(guò)程進(jìn)行封裝,使開(kāi)發(fā)者只需要關(guān)注SQL 本身,而不需要花費(fèi)精力去處理例如注冊(cè)驅(qū)動(dòng)、創(chuàng)建connection、創(chuàng)建statement、手動(dòng)設(shè)置參數(shù)、結(jié)果集檢索等jdbc繁雜的過(guò)程代碼。

Mybatis通過(guò)xml或注解的方式將要執(zhí)行的各種statement(statement、preparedStatement、CallableStatement)配置起來(lái),并通過(guò)java對(duì)象和statement中的sql進(jìn)行映射生成最終執(zhí)行的sql語(yǔ)句,最后由mybatis框架執(zhí)行sql并將結(jié)果映射成java對(duì)象并返回。

2.關(guān)于使用JDBC以及問(wèn)題總結(jié)

--jdbc編程步驟:

1.加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)

2.創(chuàng)建并獲取數(shù)據(jù)庫(kù)鏈接

3.創(chuàng)建jdbc statement對(duì)象

4.設(shè)置sql語(yǔ)句

5.設(shè)置sql語(yǔ)句中的參數(shù)(使用preparedStatement)

6.通過(guò)statement執(zhí)行sql并獲取結(jié)果

7.對(duì)sql執(zhí)行結(jié)果進(jìn)行解析處理

8.釋放資源(resultSet、preparedstatement、connection)

--jdbc程序

public static void main(String[] args) {

??? ?????? Connection connection =null;

?????????? PreparedStatementpreparedStatement =null;

?????????? ResultSetresultSet =null;

?????????? try {

????????????? //加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)

????????????? Class.forName("com.mysql.jdbc.Driver");

????????????? //通過(guò)驅(qū)動(dòng)管理類(lèi)獲取數(shù)據(jù)庫(kù)鏈接

????????????? connection=? DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");

????????????? //定義sql語(yǔ)句 ?表示占位符

?????????? String sql ="select * from user where

username = ?";

????????????? //獲取預(yù)處理statement

????????????? preparedStatement= connection.prepareStatement(sql);

????????????? //設(shè)置參數(shù),第一個(gè)參數(shù)為sql語(yǔ)句中參數(shù)的序號(hào)(從1開(kāi)始),第二個(gè)參數(shù)為設(shè)置的參數(shù)值

????????????? preparedStatement.setString(1,"王五");

????????????? //向數(shù)據(jù)庫(kù)發(fā)出sql執(zhí)行查詢,查詢出結(jié)果集

????????????? resultSet=? preparedStatement.executeQuery();

????????????? //遍歷查詢結(jié)果集

????????????? while(resultSet.next()){

????????????????? System.out.println(resultSet.getString("id")+"? "+resultSet.getString("username"));

????????????? }

?????????? }catch (Exception e) {

????????????? e.printStackTrace();

?????????? }finally{

????????????? //釋放資源

????????????? if(resultSet!=null){

????????????????? try {

???????????????????? resultSet.close();

????????????????? }catch (SQLException e) {

???????????????????? // TODO Auto-generated catch block

????????????????? ??? e.printStackTrace();

????????????????? }

????????????? }

????????????? if(preparedStatement!=null){

????????????????? try {

???????????????????? preparedStatement.close();

????????????????? }catch (SQLException e) {

???????????????????? // TODO Auto-generated catch block

???????????????????? e.printStackTrace();

????????????????? }

????????????? }

????????????? if(connection!=null){

????????????????? try {

???????????????????? connection.close();

????????????????? }catch (SQLException e) {

???????????????????? // TODO Auto-generated catch block

???????????????????? e.printStackTrace();

????????????????? }

????????????? }

?????????? }

?????? }

--問(wèn)題總結(jié)

1、 數(shù)據(jù)庫(kù)鏈接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費(fèi)從而影響系統(tǒng)性能,如果使用數(shù)據(jù)庫(kù)鏈接池可解決此問(wèn)題。

2、 Sql語(yǔ)句在代碼中硬編碼,造成代碼不易維護(hù),實(shí)際應(yīng)用sql變化的可能較大,sql變動(dòng)需要改變java代碼。

3、 使用preparedStatement向占有位符號(hào)傳參數(shù)存在硬編碼,因?yàn)閟ql語(yǔ)句的where條件不一定,可能多也可能少,修改sql還要修改代碼,系統(tǒng)不易維護(hù)。

4、 對(duì)結(jié)果集解析存在硬編碼(查詢列名),sql變化導(dǎo)致解析代碼變化,系統(tǒng)不易維護(hù),如果能將數(shù)據(jù)庫(kù)記錄封裝成pojo對(duì)象解析比較方便。?

引出Mybatis,這里使用了一個(gè)案例入門(mén)

3.Mybatis的架構(gòu)圖

1、 mybatis配置 SqlMapConfig.xml,此文件作為mybatis的全局配置文件,配置了mybatis的運(yùn)行環(huán)境等信息。 mapper.xml文件即sql映射文件,文件中配置了操作數(shù)據(jù)庫(kù)的sql語(yǔ)句。此文件需要在SqlMapConfig.xml中加載。

2、 通過(guò)mybatis環(huán)境等配置信息構(gòu)造SqlSessionFactory即會(huì)話工廠

3、 由會(huì)話工廠創(chuàng)建sqlSession即會(huì)話,操作數(shù)據(jù)庫(kù)需要通過(guò)sqlSession進(jìn)行。

4、 mybatis底層自定義了Executor執(zhí)行器接口操作數(shù)據(jù)庫(kù),Executor接口有兩個(gè)實(shí)現(xiàn),一個(gè)是基本執(zhí)行器、一個(gè)是緩存執(zhí)行器。

5、 Mapped Statement也是mybatis一個(gè)底層封裝對(duì)象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個(gè)sql對(duì)應(yīng)一個(gè)Mapped Statement對(duì)象,sql的id即是Mapped statement的id。

6、 Mapped Statement對(duì)sql執(zhí)行輸入?yún)?shù)進(jìn)行定義,包括HashMap、基本類(lèi)型、pojo,Executor通過(guò)Mapped Statement在執(zhí)行sql前將輸入的java對(duì)象映射至sql中,輸入?yún)?shù)映射就是jdbc編程中對(duì)preparedStatement設(shè)置參數(shù)。

7、 Mapped Statement對(duì)sql執(zhí)行輸出結(jié)果進(jìn)行定義,包括HashMap、基本類(lèi)型、pojo,Executor通過(guò)Mapped Statement在執(zhí)行sql后將輸出結(jié)果映射至java對(duì)象中,輸出結(jié)果映射過(guò)程相當(dāng)于jdbc編程中對(duì)結(jié)果的解析處理過(guò)程。

4.Mybatis案例入門(mén)

4.1 需求:

實(shí)現(xiàn)以下功能:

根據(jù)用戶id查詢一個(gè)用戶信息

根據(jù)用戶名稱(chēng)模糊查詢用戶信息列表

添加用戶? ? 更新用戶? ? 刪除用戶?

4.2 項(xiàng)目工程的搭建:

第一步:創(chuàng)建Java工程

第二步:加入jar包(mybatis核心包、依賴包、數(shù)據(jù)驅(qū)動(dòng)包)

第三步:在classpath下創(chuàng)建log4j.properties(mybatis默認(rèn)使用log4j作為輸出日志信息)

第四步:在classpath下創(chuàng)建SqlMapConfig.xml(SqlMapConfig.xml是mybatis核心配置文件,上邊文件的配置內(nèi)容為數(shù)據(jù)源、事務(wù)管理)

第五步:po類(lèi)(Po類(lèi)作為mybatis進(jìn)行sql映射使用,po類(lèi)通常與數(shù)據(jù)庫(kù)表對(duì)應(yīng))

第六步:sql映射文件

第七步:加載映射文件(mybatis框架需要加載映射文件,將Users.xml添加在SqlMapConfig.xml)

4.3 根據(jù)id查詢用戶信息

4.3.1?user.xml映射文件

parameterType:定義輸入到sql中的映射類(lèi)型

#{id}表示使用preparedstatement設(shè)置占位符號(hào)并將輸入變量id傳到sql

resultType:定義結(jié)果映射類(lèi)型

4.3.2?測(cè)試程序

4.4?根據(jù)用戶名查詢用戶信息

4.4.1?映射文件(user.xml)

4.4.2?測(cè)試程序

4.5?上面4.3和4.4的小結(jié)

4.5.1 #{}和${}

#{}表示一個(gè)占位符號(hào),通過(guò)#{}可以實(shí)現(xiàn)preparedStatement向占位符中設(shè)置值,自動(dòng)進(jìn)行java類(lèi)型和jdbc類(lèi)型轉(zhuǎn)換,#{}可以有效防止sql注入。 #{}可以接收簡(jiǎn)單類(lèi)型值或pojo屬性值。 如果parameterType傳輸單個(gè)簡(jiǎn)單類(lèi)型值,#{}括號(hào)中可以是value或其它名稱(chēng)。

${}表示拼接sql串,通過(guò)${}可以將parameterType 傳入的內(nèi)容拼接在sql中且不進(jìn)行jdbc類(lèi)型轉(zhuǎn)換, ${}可以接收簡(jiǎn)單類(lèi)型值或pojo屬性值,如果parameterType傳輸單個(gè)簡(jiǎn)單類(lèi)型值,${}括號(hào)中只能是value。

4.5.2 parameterType和resultType

parameterType:指定輸入?yún)?shù)類(lèi)型,mybatis通過(guò)ognl從輸入對(duì)象中獲取參數(shù)值拼接在sql中。 resultType:指定輸出結(jié)果類(lèi)型,mybatis將sql查詢結(jié)果的一行記錄數(shù)據(jù)映射為resultType指定類(lèi)型的對(duì)象。

4.5.3?selectOne和selectList

selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則拋出異常: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3 ??? at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70) ?

selectList可以查詢一條或多條記錄。

4.6?添加用戶

4.6.1?映射文件

4.6.2?測(cè)試程序

4.7?mysql自增主鍵返回(通過(guò)修改sql映射文件,可以將mysql自增主鍵返回)

添加selectKey實(shí)現(xiàn)將主鍵返回

keyProperty:返回的主鍵存儲(chǔ)在pojo中的哪個(gè)屬性

order:selectKey的執(zhí)行順序,是相對(duì)與insert語(yǔ)句來(lái)說(shuō),由于mysql的自增原理執(zhí)行完insert語(yǔ)句之后才將主鍵生成,所以這里selectKey的執(zhí)行順序?yàn)閍fter resultType:返回的主鍵是什么類(lèi)型

LAST_INSERT_ID():是mysql的函數(shù),返回auto_increment自增列新記錄id值。

--使用 uuid實(shí)現(xiàn)主鍵

4.8?刪除用戶

4.8.1?映射文件

4.8.2?測(cè)試程序

4.9?修改用戶

4.9.1?映射文件

4.9.2?測(cè)試程序

5??Mybatis解決jdbc編程的問(wèn)題

1、 數(shù)據(jù)庫(kù)鏈接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費(fèi)從而影響系統(tǒng)性能,如果使用數(shù)據(jù)庫(kù)鏈接池可解決此問(wèn)題。

解決:在SqlMapConfig.xml中配置數(shù)據(jù)鏈接池,使用連接池管理數(shù)據(jù)庫(kù)鏈接。

2、 Sql語(yǔ)句寫(xiě)在代碼中造成代碼不易維護(hù),實(shí)際應(yīng)用sql變化的可能較大,sql變動(dòng)需要改變java代碼。

解決:將Sql語(yǔ)句配置在XXXXmapper.xml文件中與java代碼分離。

3、 向sql語(yǔ)句傳參數(shù)麻煩,因?yàn)閟ql語(yǔ)句的where條件不一定,可能多也可能少,占位符需要和參數(shù)一一對(duì)應(yīng)。

解決:Mybatis自動(dòng)將java對(duì)象映射至sql語(yǔ)句,通過(guò)statement中的parameterType定義輸入?yún)?shù)的類(lèi)型。 4、 對(duì)結(jié)果集解析麻煩,sql變化導(dǎo)致解析代碼變化,且解析前需要遍歷,如果能將數(shù)據(jù)庫(kù)記錄封裝成pojo對(duì)象解析比較方便。

解決:Mybatis自動(dòng)將sql執(zhí)行結(jié)果映射至java對(duì)象,通過(guò)statement中的resultType定義輸出結(jié)果的類(lèi)型。

6?原始Dao開(kāi)發(fā)方式(需要編寫(xiě)Dao接口和Dao實(shí)現(xiàn)類(lèi))

6.1?映射文件

6.2?Dao接口及實(shí)現(xiàn)類(lèi)

--接口

--實(shí)現(xiàn)類(lèi)

6.3?測(cè)試

6.4?問(wèn)題

原始Dao開(kāi)發(fā)中存在以下問(wèn)題:

1.Dao方法體存在重復(fù)代碼:通過(guò)SqlSessionFactory創(chuàng)建SqlSession,調(diào)用SqlSession的數(shù)據(jù)庫(kù)操作方法

2.調(diào)用sqlSession的數(shù)據(jù)庫(kù)操作方法需要指定statement的id,這里存在硬編碼,不利于開(kāi)發(fā)維護(hù)。

7?Mapper動(dòng)態(tài)代理方式(重要)

7.1?開(kāi)發(fā)規(guī)范

Mapper接口開(kāi)發(fā)方法只需要程序員編寫(xiě)Mapper接口(相當(dāng)于Dao接口),由Mybatis框架根據(jù)接口定義創(chuàng)建接口的動(dòng)態(tài)代理對(duì)象,代理對(duì)象的方法體同上邊Dao接口實(shí)現(xiàn)類(lèi)方法。

Mapper接口開(kāi)發(fā)需要遵循以下規(guī)范:

1、 Mapper.xml文件中的namespace與mapper接口的類(lèi)路徑相同。

2、 Mapper接口方法名和Mapper.xml中定義的每個(gè)statement的id相同

3、 Mapper接口方法的輸入?yún)?shù)類(lèi)型和mapper.xml中定義的每個(gè)sql 的parameterType的類(lèi)型相同

4、 Mapper接口方法的輸出參數(shù)類(lèi)型和mapper.xml中定義的每個(gè)sql的resultType的類(lèi)型相同

7.2?Mapper.xml(映射文件)

定義mapper映射文件UserMapper.xml(內(nèi)容同Users.xml),需要修改namespace的值為 UserMapper接口路徑。將UserMapper.xml放在classpath 下mapper目錄 下。

7.3?接口文件(Mapper.java)

--接口定義的規(guī)則:

1、 Mapper接口方法名和Mapper.xml中定義的statement的id相同

2、 Mapper接口方法的輸入?yún)?shù)類(lèi)型和mapper.xml中定義的statement的parameterType的類(lèi)型相同

3、 Mapper接口方法的輸出參數(shù)類(lèi)型和mapper.xml中定義的statement的resultType的類(lèi)型相同

7.4?加載UserMapper.xml文件(修改SqlMapConfig.xml文件)

7.5?測(cè)試

8 Mybatis和hibernate的區(qū)別

Mybatis和hibernate不同,它不完全是一個(gè)ORM框架,因?yàn)镸yBatis需要程序員自己編寫(xiě)Sql語(yǔ)句,不過(guò)mybatis可以通過(guò)XML或注解方式靈活配置要運(yùn)行的sql語(yǔ)句,并將java對(duì)象和sql語(yǔ)句映射生成最終執(zhí)行的sql,最后將sql執(zhí)行的結(jié)果再映射生成java對(duì)象。

Mybatis學(xué)習(xí)門(mén)檻低,簡(jiǎn)單易學(xué),程序員直接編寫(xiě)原生態(tài)sql,可嚴(yán)格控制sql執(zhí)行性能,靈活度高,非常適合對(duì)關(guān)系數(shù)據(jù)模型要求不高的軟件開(kāi)發(fā),例如互聯(lián)網(wǎng)軟件、企業(yè)運(yùn)營(yíng)類(lèi)軟件等,因?yàn)檫@類(lèi)軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無(wú)法做到數(shù)據(jù)庫(kù)無(wú)關(guān)性,如果需要實(shí)現(xiàn)支持多種數(shù)據(jù)庫(kù)的軟件則需要自定義多套sql映射文件,工作量大。

Hibernate對(duì)象/關(guān)系映射能力強(qiáng),數(shù)據(jù)庫(kù)無(wú)關(guān)性好,對(duì)于關(guān)系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開(kāi)發(fā)可以節(jié)省很多代碼,提高效率。但是Hibernate的學(xué)習(xí)門(mén)檻高,要精通門(mén)檻更高,而且怎么設(shè)計(jì)O/R映射,在性能和對(duì)象模型之間如何權(quán)衡,以及怎樣用好Hibernate需要具有很強(qiáng)的經(jīng)驗(yàn)和能力才行。

總之,按照用戶的需求在有限的資源環(huán)境下只要能做出維護(hù)性、擴(kuò)展性良好的軟件架構(gòu)都是好架構(gòu),所以框架只有適合才是最好。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容