mybatis總結



1.mybatis的工作原理

1:使用連接池,datasource,在驅動並連接的這個過程中優化並解耦

JDBC第一步其實從效率角度來看是不合適的,因為無論什么數據庫都不可能支撐隨機和龐大的連接數,而且不可避免的存在連接浪費的情況,Mybatis就封裝了這些優化的方法。

2:統一sql存取到XML

如果代碼寫在java塊中,在團隊合作中很可能出現兩個交叉業務的代碼使用類似的sql語句,而開發人員的工作本身沒有交集,那就代表sql語句肯定是無法復用的。而且對sql的修改,就代表着對java文件的修改,需要重新編譯和打包部署(比如常見的狀態值更改,sql修改隨着業務變化必然存在修改)。

mybatis將sql統一存取到xml中,就算存在業務交叉,但因為統一配置的緣故,sql在xml中一目了然,兩個跨team的程序員可以看到對方的sql,來判斷自己是否需要重用。並且使用xml配置可以減少代碼編譯。

3:參數和結果集映射

sql的方式需要傳入參數,如果存在多條件“或類型”的查詢(列表查詢的查詢條件允許空),那就代表你必須傳參進行sql拼接,就算使用xml的方式也不行。要么每個業務獨立配置xml中的sql,要么還是寫入java代碼中,或者以工具的方式進行自動拼接。

Mybatis使用映射的方式,方便model管理參數,同時以解析器的方式將參數動態拼接到sql(sqlmaper里那些標簽),由於是model映射,連查詢結果都可以統一映射,方便取出和運算。而且mybatis對查詢結果集進行了緩存處理,使得重復查詢進一步進行了優化。

4:對多重復sql進行復用封裝

比如模板方法,將常用sql模塊化,直接調用。比如通用的save和getID之類的,只有表名和字段名有變化。


2.mybatis跟hibante的比較, 優缺點.

hibernate是全自動,而mybatis是半自動。
hibernate完全可以通過對象關系模型實現對數據庫的操作,擁有完整的JavaBean對象與數據庫的映射結構來自動生成sql。
而mybatis僅有基本的字段映射,對象數據以及對象實際關系仍然需要通過手寫sql來實現和管理。
2. hibernate數據庫移植性遠大於mybatis。
hibernate通過它強大的映射結構和hql語言,大大降低了對象與數據庫(Oracle、MySQL等)的耦合性,而mybatis由於需要手寫sql,
因此與數據庫的耦合性直接取決於程序員寫sql的方法,如果sql不具通用性而用了很多某數據庫特性的sql語句的話
,移植性也會隨之降低很多,成本很高。
3. hibernate擁有完整的日志系統,mybatis則欠缺一些。
hibernate日志系統非常健全,涉及廣泛,包括:sql記錄、關系異常、優化警告、緩存提示、臟數據警告等;
而mybatis則除了基本記錄功能外,功能薄弱很多。
4. mybatis相比hibernate需要關心很多細節
hibernate配置要比mybatis復雜的多,學習成本也比mybatis高。但也正因為mybatis使用簡單,才導致它要比hibernate關心很多技術細節。
mybatis由於不用考慮很多細節,開發模式上與傳統jdbc區別很小,因此很容易上手並開發項目,
但忽略細節會導致項目前期bug較多,因而開發出相對穩定的軟件很慢,而開發出軟件卻很快。
hibernate則正好與之相反。但是如果使用hibernate很熟練的話,實際上開發效率絲毫不差於甚至超越mybatis。
5. sql直接優化上,mybatis要比hibernate方便很多
由於mybatis的sql都是寫在xml里,因此優化sql比hibernate方便很多。
而hibernate的sql很多都是自動生成的,無法直接維護sql;
雖有hql,但功能還是不及sql強大,見到報表等變態需求時,hql也歇菜,也就是說hql是有局限的;
hibernate雖然也支持原生sql,但開發模式上卻與orm不同,需要轉換思維,因此使用上不是非常方便。
總之寫sql的靈活度上hibernate不及mybatis。

總結:
mybatis:小巧、方便、高效、簡單、直接、半自動
hibernate:強大、方便、高效、復雜、繞彎子、全自動

mybatis:
1. 入門簡單,即學即用,提供了數據庫查詢的自動對象綁定功能,而且延續了很好的SQL使用經驗,對於沒有那么高的對象模型要求的項目來說,相當完美。
2. 可以進行更為細致的SQL優化,可以減少查詢字段。
3. 缺點就是框架還是比較簡陋,功能尚有缺失,雖然簡化了數據綁定代碼,但是整個底層數據庫查詢實際還是要自己寫的,工作量也比較大,而且不太容易適應快速數據庫修改。
4. 二級緩存機制不佳。
hibernate:
1. 功能強大,數據庫無關性好,O/R映射能力強,如果你對Hibernate相當精通,而且對Hibernate進行了適當的封裝,那么你的項目整個持久層代碼會相當簡單,需要寫的代碼很少,開發速度很快,非常爽。
2. 有更好的二級緩存機制,可以使用第三方緩存。
3. 缺點就是學習門檻不低,要精通門檻更高,而且怎么設計O/R映射,在性能和對象模型之間如何權衡取得平衡,以及怎樣用好Hibernate方面需要你的經驗和能力都很強才行。
舉個形象的比喻:
mybatis:機械工具,使用方便,拿來就用,但工作還是要自己來作,不過工具是活的,怎么使由我決定。??
hibernate:智能機器人,但研發它(學習、熟練度)的成本很高,工作都可以擺脫他了,但僅限於它能做的事。??

 

3.mybatis跟jdbc的比較,優缺點;
1. DAO層代碼可以通過現有插件直接生成,大大提高編碼效率和准確性。
2. mybatis已有的連接池管理,緩存管理等所帶來的代碼性能優勢和可靠性。
3. 一致的編碼風格大大減少代碼的溝通成本;
4. mybatis提供了一級和二級緩存(需要配置打開),強大的動態sql,自動化的session管理,都比手工維護來的方便和安全。
5. 不用重復寫resultset到domain的轉化了。
6. 相似的sql不需要重復寫。

 

4.如何理解"全自動"和"半自動"的概念;
hibernate完全可以通過對象關系模型實現對數據庫的操作,擁有完整的JavaBean對象與數據庫的映射結構來自動生成sql。
而mybatis僅有基本的字段映射,對象數據以及對象實際關系仍然需要通過手寫sql來實現和管理。


5.mybatis中的#和$的區別?
1. #將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。
如:order by #user_id#,如果傳入的值是111,那么解析成sql時的值為order by "111",
如果傳入的值是id,則解析成的sql為order by "id".
  
2. $將傳入的數據直接顯示生成在sql中。
如:order by $user_id$,如果傳入的值是111,那么解析成sql時的值為order by user_id,
如果傳入的值是id,則解析成的sql為order by id.
  
3. #方式能夠很大程度防止sql注入。
  
4.$方式無法防止Sql注入。

5.$方式一般用於傳入數據庫對象,例如傳入表名.
  
6.一般能用#的就別用$.


MyBatis排序時使用order by 動態參數時需要注意,用$而不是#


字符串替換
默認情況下,使用#{}格式的語法會導致MyBatis創建預處理語句屬性並以它為背景設置安全的值(比如?)。
這樣做很安全,很迅速也是首選做法,有時你只是想直接在SQL語句中插入一個不改變的字符串。
比如,像ORDER BY,你可以這樣來使用:
ORDER BY ${columnName}
這里MyBatis不會修改或轉義字符串。
重要:接受從用戶輸出的內容並提供給語句中不變的字符串,這樣做是不安全的。
這會導致潛在的SQL注入攻擊,因此你不應該允許用戶輸入這些字段,或者通常自行轉義並檢查。


6.mybatis中如何使用動態sql
MyBatis的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其他類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句有多么痛苦。拼接的時候要確保不能忘了必要的空格,還要注意省掉列名列表最后的逗號。有些時候,SQL語句where條件中,需要一些安全判斷,例如按某一條件查詢時如果傳入的參數是空,此時查詢出的結果很可能是空的,也許我們需要參數為空時,是查出全部的信息。使用Oracle的序列、mySQL的函數生成Id。這時我們可以使用動態SQL。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。通常使用動態 SQL 不可能是獨立的一部分,MyBatis 當然使用一種強大的動態 SQL 語言來改進這種情形,這種語言可以被用在任意的 SQL 映射語句中。動態 SQL 元素和使用 JSTL 或其他類似基於 XML 的文本處理器相似。MyBatis 采用功能強大的基於 OGNL 的表達式來消除其他元素。
MyBatis中用於實現動態SQL的元素主要有:
1、if和where
2、choose(when,otherwise)
3、trim
4、set
5、foreach
下面將逐一進行介紹。

二、動態SQL的元素詳解
首先來介紹一下SQL片段,它可以把動態SQL的判斷部分獨立處理,以便其他查詢進行復用。
SQL片段定義方式:
[java] view plain copy print?
<!--
定義sql片段
id是sql片段的唯一標識,便於下面語句的引用。通常把SQL片段設計成基於單表來定義sql片段,這樣話這個sql片段可重用性才高。
注意:在sql片段中不要包括 where
-->
<sql id="query_user_where">

<if >

</if>
<foreach >


</foreach>

<!--其他語句塊-->

</sql>

引用SQL片段
[java] view plain copy print?
<where>
<!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前邊加namespace -->
<include refid="query_user_where"></include>
<!-- 在這里還可以引用其它的sql片段 -->
</where>

1、if和where
if就是簡單的條件判斷,利用if語句我們可以實現某些簡單的條件選擇。動態 SQL 通常要做的事情是有條件地包含 where 子句的一部分。
使用示例:
查詢語句塊:
[java] view plain copy print?
<select id="findUserList" parameterType="com.kang.pojo.UserQueryVo"
resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER
<!--
where可以自動去掉條件中的第一個and
-->
<where>
<include refid="query_user_where"></include>
</where>
</select>


where元素的作用是會在寫入where元素的地方輸出一個where,另外一個好處是你不需要考慮where元素里面的條件輸出是什么樣子的,MyBatis會智能的幫你處理。如果所有的條件都不滿足那么MyBatis就會查出所有的記錄;如果輸出后是and這個單詞開頭的,MyBatis會把第一個單詞and忽略,當然如果是or開頭的,MyBatis也會把它忽略。此外,在where元素中你不需要考慮空格的問題,MyBatis會智能的幫你加上。
SQL片段:
[java] view plain copy print?
<sql id="query_user_where">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username LIKE '%${userCustom.username}%'
</if>
</if>
</sql>
上述配置意思非常簡單,如果你提供了sex參數,那么就要滿足sex!=null和sex!=''兩個條件,同樣如果你提供了username參數的時候,也需要滿足相應的條件,之后就是返回滿足這些條件的所有user,這是非常有用的一個功能,以往我們使用其他類型框架或者直接使用JDBC的時候, 如果我們要達到同樣的選擇效果的時候,我們就需要拼SQL語句,這是極其麻煩的,比起來,上述的動態SQL就要簡單多了。
如果輸入是sex=1和username=null,那么上述配置產生的SQL語句就是:
SELECT * FROM USER where user.sex = #{userCustom.sex}
而不是:
SELECT * FROM USER and user.sex = #{userCustom.sex}
因為where標簽自動加入了"where"這個關鍵字,而且去掉了"and"這個單詞,並在where的前后自動加入了空格,最終組合成相應的SQL語句。

2、choose
choose元素的作用就相當於JAVA中的switch語句,基本上跟JSTL中的choose的作用和用法是一樣的,通常都是與when和otherwise搭配的。
使用示例:
[java] view plain copy print?
<select id="findUserList" parameterType="com.kang.pojo.UserQueryVo"
resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER
<choose>
<when test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex = #{userCustom.sex}
</when>
<when test="userCustom.username!=null and userCustom.username!=''">
and user.username LIKE '%${userCustom.username}%'
</when>
<otherwise>
and user.id = 1
</otherwise>
</choose>
</select>

上述配置中,when元素表示當when中的條件滿足的時候就輸出其中的內容,跟JAVA中的switch效果差不多的是按照條件的順序,當when中有條件滿足的時候,就會跳出choose,即所有的when和otherwise條件中,只有一個會輸出,當所有的條件都不滿足的時候就輸出otherwise中的內容。

3、trim
trim元素的主要功能是可以在自己包含的內容前加上某些前綴,也可以在其后加上某些后綴,與之對應的屬性是prefix和suffix;可以把包含內容的首部某些內容覆蓋,即忽略,也可以把尾部的某些內容覆蓋,對應的屬性是prefixOverrides和suffixOverrides;正因為trim有這樣的功能,所以我們也可以非常簡單的利用trim來代替where元素的功能。
使用示例:
[java] view plain copy print?
<select id="findUserList" parameterType="com.kang.pojo.UserQueryVo"
resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER
<trim prefix="where" prefixOverrides="and |or">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username LIKE '%${userCustom.username}%'
</if>
</if>
</trim>
</select>

4、set
set元素主要是用在更新操作的時候,它的主要功能和where元素其實是差不多的,主要是在set標簽包含的語句前輸出一個set。如果包含的語句是以逗號結束的話將會把該逗號忽略。如果set包含的內容為空的話則會出錯。有了set元素我們就可以動態的更新那些修改了的字段,而不用每次更新全部字段。
使用示例:
[java] view plain copy print?
<update id="updateUser" parameterType="com.kang.pojo.User">
update user
<set>
<if test="username != null">
username=#{username},
</if>
<if test="birthday != null">
birthday=#{birthday},
</if>
<if test="sex != null">
sex=#{sex},
</if>
<if test="address != null">
address=#{address}
</if>
</set>
where id = #{id}
</update>

5、foreach
foreach的主要用在構建in條件中,它可以在SQL語句中迭代一個集合。foreach元素的屬性主要有item,index,collection,open,separator,close。
item表示集合中每一個元素進行迭代時的別名,index指定一個名字,用於表示在迭代過程中,每次迭代到的位置,open表示該語句以什么開始,separator表示在每次進行迭代之間以什么符號作為分隔符,close表示以什么結束。
collection屬性用於指定傳入參數的類型。該屬性是必須指定的,在不同情況下,該屬性的值是不一樣的,主要有一下3種情況:
如果傳入的是單參數且參數類型是一個List類型的時候,collection屬性值為list。
如果傳入的是單參數且參數類型是一個array數組的時候,collection的屬性值為array。
如果傳入的參數是多個的時候,我們就需要把它們封裝成一個Map了,當然單參數也可以封裝成map。實際上在傳入參數的時候,MyBatis也是把它封裝成一個Map的,List實例將會以“list”作為鍵,而數組實例將會以“array”作為鍵。這個時候collection屬性值就是傳入的List或array對象在封裝自身的map里面中的對應key。
傳入List的使用示例:
首先是查詢接口:
public List<User> findUserList(List<Integer> ids);
對應xml文件中的配置:
[java] view plain copy print?
<select id="findUserList" resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER WHERE id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{ids}
</foreach>
</select>
可以看到,foreach標簽描述中的參數和接口中的輸入參數保持一致。
具體代碼使用:
[java] view plain copy print?
//前述代碼略
UserMapper userMapper = session.getMapper(UserMapper.class);
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(3);
ids.add(6);
List<user> users = userMapper.findUserList(ids);
for (User user : users)
System.out.println(user);
session.close();

傳入array數組的使用示例:
接口定義:
public List<User> findUserList(int[] ids);
對應xml文件中的配置:
[java] view plain copy print?
<select id="findUserList" resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER WHERE id IN
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{ids}
</foreach>
</select>

具體代碼使用:
//前述代碼略
[java] view plain copy print?
UserMapper userMapper = session.getMapper(UserMapper.class);
int[] ids = {1,3,6,9};
List<user> users = userMapper.findUserList(ids);
for (User user : users)
System.out.println(user);
session.close();
傳入array數組的使用示例:
接口定義:
public List<User> findUserList(Map<String, Object> params);
對應xml文件中的配置:
[java] view plain copy print?
<select id="findUserList" resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER WHERE id IN
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{params}
</foreach>
</select>

具體代碼使用:
[java] view plain copy print?
//前述代碼略
UserMapper userMapper = session.getMapper(UserMapper.class);
final List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(6);
ids.add(7);
ids.add(9);
Map<String, Object> params = new HashMap<String, Object>();
params.put("ids", ids);
List<user> users = userMapper.findUserList(ids);
for (User user : users)
System.out.println(user);
session.close();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM