...敬請期待session
經過上一篇的入門MyBatis學習筆記(1)—使用篇,能夠發現除了一些基本配置外,Mybatis的精華就在於Mapper(映射)部分。Mybatis是針對映射器構造的SQL構建的輕量級框架,而且能夠經過配置生成對應的JavaBean給調用者。在Mybatis中能夠靈活使用SQL來知足各類不一樣場景的需求,因此在互聯網企業內更偏心於使用Mybatis來應對高速變化的需求,而傳統企業更偏向於使用Hibernate。mybatis
上一節咱們僅僅定義了一個select語句:app
<mapper namespace="com.shuqing28.dao.CommodityDao">
<select id="getAllCommodity" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity
</select>
</mapper>
複製代碼
實際上增刪改查在Mybatis映射器裏面都有對應的元素框架
元素名稱 | 描述 | 備註 |
---|---|---|
select | 查詢語句,最經常使用的 | 能夠自定義參數,返回結果集 |
insert | 插入語句 | 執行後返回一個整數,表明插入的條數 |
update | 更新語句 | 執行後返回一個整數,表明更新的條數 |
delete | 刪除語句 | 執行後返回一個整數,表明刪除的條數 |
parameterMap | 定義參數映射關係 | 即將被刪除的元素,不建議使用 |
sql | 容許定義一部分的SQL,而後在各個地方引用 | 例如,定義一個表名,在其它地方的SQL語句中使用 |
resultMap | 用來描述從數據庫結果集中加載對象 | 它將提供映射規則 |
cache | 給定命名空間的緩存配置 | ———— |
cache-ref | 其餘命名空間緩存配置的引用 | ———— |
下面咱們探究主要使用的幾個元素post
select元素是咱們最經常使用的元素,正如在SQL裏是查詢功能也是最主要的功能之一。在咱們常識裏,查詢語句一般都是根據一個或者多個條件,查詢數據庫返回一個,多個或者全部字段。以前咱們舉得getAllCommodity
沒有查詢條件,返回全部字段。學習
在Mybatis裏,咱們能夠傳入簡單的參數類型,像int,float,String這些,也能夠傳入一些複雜的類型,好比JavaBean、Map之流的,Mybatis把這些參數轉換成SQL語句須要的類型後,返回結果,而且經過映射,將結果集自動綁定到JavaBean中,因此JDBC裏面那一套一個一個從ResultSet獲取值的操做都被省略了。
下面咱們看一個有參數的select語句:
<select id="getCommodityById" parameterType="int" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity where id=#{id}
</select>
複製代碼
同時咱們定義了接口方法:
Commodity getCommodityById(Integer id);
複製代碼
不一樣於getAllCommodity
沒有傳入參數,getCommodityById
有一個int類型的傳入參數,返回的仍是Commodity。 上面的select語句包含如下屬性:
這裏看resultType,咱們查詢的是commodity的全部字段,再次回顧字段定義:
字段名 | 類型 |
---|---|
id | int |
name | varchar(255) |
price | decimal(8,2) |
description | varchar(255) |
而咱們的POJO類包含:
private Integer id;
private String name;
private Double price;
private String description;
複製代碼
這裏Mybatis幫咱們完成了自動映射,只要返回的SQL列名和JavaBean的屬性一致,Mybatis就能夠幫助咱們自動回填這些字段而無需任何配置。咱們能夠再Mybatis的配置文件裏,經過autoMappingBehavior來設置自動映射,它包含3個值:
剛纔咱們舉例的是隻傳遞了一個參數,若是傳遞多個參數呢?這時候就要說說輸入映射了。
傳遞多個參數一般來講有3種方式,經過Map,經過註解,以及經過POJO對象
假設咱們想查詢帶有餅的食物,而且價格低於80的。那麼咱們能夠這麼寫SQL語句
<select id="getCommodityByMap" parameterType="map" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity WHERE name like '%${name}%' AND price<#{price}
</select>
複製代碼
由於mybatis使用xml定義Mapper,因此這裏'<'用了轉義符<
表示,其實仍是同樣的。 parameterType定義爲map,咱們定義的接口也是接受Map做爲參數
List<Commodity> getCommodityByMap(Map<String, Object> params);
複製代碼
使用:
CommodityDao commodityDao = sqlSession.getMapper(CommodityDao.class);
Map<String, Object> paramsMap = new HashMap<String , Object>();
paramsMap.put("name", "餅");
paramsMap.put("price", 80.0);
List<Commodity> commodities = commodityDao.getCommodityByMap(paramsMap);
複製代碼
最後打印commodities:
[Commodity{id=1001, name='野葡萄烤餅', price=10.0, description='吃完還有點餓'}, Commodity{id=1003, name='南瓜百吉餅', price=50.0, description='份大量足,能夠去很遠的地方'}]
複製代碼
雖然Map很簡單,可是光是看傳入參數Map,你不知道包含了怎樣的內容,如果深刻還得看如何設置Map的,並且使用時還要一項項指定Map的Key的名字,因此不怎麼提倡使用了。
註解方式使用了**@Param**註解,咱們這樣定義接口:
List<Commodity> getCommodityByAnnation(@Param("name") String name, @Param("price") Double price);
複製代碼
Mybatis根據@Param提供的名稱,把變量值傳到SQL語句中對應的參數中,參數的可讀性大大提升,可是不足之處在於,如果參數不少,一個一個寫很麻煩,下降了可讀性。
因此最常用的仍是利用POJO傳遞參數。
一般咱們只須要傳遞簡單的POJO對象就能夠了,好比咱們這樣定義select元素:
<select id="getCommodityByPOJO" parameterType="com.shuqing28.pojo.Commodity" resultType="com.shuqing28.pojo.Commodity">
SELECT * FROM commodity WHERE name like '%${name}%' AND price<#{price}
</select>
複製代碼
測試:
@Test
public void getLowPriceCommodityByPOJO(){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
CommodityDao commodityDao = sqlSession.getMapper(CommodityDao.class);
Commodity commodity = new Commodity();
commodity.setName("餅");
commodity.setPrice(80.0);
List<Commodity> commodities = commodityDao.getCommodityByPOJO(commodity);
System.out.println(commodities);
} finally {
sqlSession.close();
}
}
複製代碼
也會返回和上面同樣的結果,這裏Mybatis會把POJO裏對應的屬性值傳到SQL裏,而後返回結果,注意看傳入參數就是POJO的徹底限定名,和ResultType是同樣的,其實能夠經過別名減小名稱的長度,咱們只須要在mybatis-config.xml
中的configuration中定義:
<typeAliases>
<typeAlias alias="commodity" type="com.shuqing28.pojo.Commodity" />
</typeAliases>
複製代碼
就能夠用commodity替換全部的全稱了,可是不能有重名的,不然會出錯。
有些負責的狀況,咱們須要定義POJO做爲查詢參數,好比上面的例子,你只須要兩個輸入參數,你也能夠定製一個只包含這兩個參數的POJO。
public class CommodityCustom {
private String name;
private Double price;
複製代碼
固然使用過程仍是同樣的,定義本身包裝過的POJO一般用來解決傳入查詢條件很複雜的狀況,好比設計到幾張表聯查的,這時候原先定義的POJO解決不了問題,就須要定義一些複合的POJO。
在輸入參數中還有個常常被提到的問題,即#和$的區別
Mybatis自己是基於JDBC封裝的。因此#{para}
是預編譯處理(PreparedStatement
),至關於原來的?
,而${para}
是字符串替換。Mybatis在處理#時,會調用PreparedStatement
的set
系列方法來賦值;處理$
時,就是把${para}
替換成變量的值。#
方式可以很大程度防止sql
注入,$
方式通常用於傳入數據庫對象,例如傳入表名,通常能用#
的就別用$
.
說完輸入咱們說輸出映射。
MyBatis的輸出映射分爲兩種方式,resultType和resultMap
咱們上面全部的例子裏都是定義的resultType,resultType能夠是簡單類型,好比咱們想獲取商品數量啊之類的,還有就是輸出POJO對象或者POJO列表。
不論是POJO對象仍是POJO列表,咱們在resultType中的定義都是同樣的,只不過接口定義不同:
Commodity getCommodityById(Integer id);
複製代碼
Mybatis根據接口返回值判斷返回一條對象,若是用過ibatis的能夠知道內部調用了session.selectOne。
List<Commodity> getCommodityByPOJO(Commodity commodity);
複製代碼
內部使用session.selectList,Mapper接口使用List<XXX>
做爲返回值。
查詢出來的列名和POJO屬性只要有一個一致就會建立POJO對象,頂多別的字段爲默認值,可是若是所有不一致,就不會建立該POJO對象了。
上面的resultType在查詢的列名和POJO屬性值一致的時候才能夠映射成功,若是不一致的話,就須要resultMap登場表演了。
若是查詢出來的列名和POJO的屬性名不一致,經過定義一個resultMap對列名和POJO屬性名之間做一個映射關係。
在使用resultMap前咱們須要定義resultMap 假設咱們查詢商品類的兩個字段id和name,可是查詢的時候定義爲id_
和name_
。列名和屬性名不一致了,先定義resultMap
<resultMap id="commodityResultMap" type="commodity">
<id column="id_" property="id"/>
<result column="name_" property="name"/>
</resultMap>
複製代碼
其中
再看咱們的select元素:
<select id="getCommodityByPrice" parameterType="double" resultMap="commodityResultMap">
SELECT id id_, name name_ FROM USER WHERE price=#{price}
</select>
複製代碼
使用resultType進行輸出映射時,只有查詢出來的列名和pojo中的屬性名一致,該列才能夠映射成功。若是查詢出來的列名和pojo的屬性名不一致,經過定義一個resultMap對列名和pojo屬性名之間做一個映射關係。 此外,resultMap還能夠作一對多、多對多等高級映射,這些內容將在後續文章中介紹。
insert相對於select簡單不少,下面是往商品表插入一個商品的實例:
<insert id="insertCommodity" useGeneratedKeys="true"
keyProperty="id">
insert into commodity (name,price,description)
values (#{name},#{price},#{description})
</insert>
複製代碼
接口爲:
void insertCommodity(Commodity commodity);
複製代碼
這裏咱們注意到了insert語句裏多了兩個屬性useGeneratedKeys
和keyProperty
,這裏涉及到的是主鍵回填的概念。
@Test
public void insertCommodity(){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
CommodityDao commodityDao = sqlSession.getMapper(CommodityDao.class);
Commodity commodity = new Commodity();
//commodity.setId(1005);
commodity.setName("艾蒿小麥餅");
commodity.setPrice(100.0);
commodity.setDescription("像在豔陽下戀愛");
commodityDao.insertCommodity(commodity);
System.out.println(commodity.getId());
} finally {
sqlSession.close();
}
}
複製代碼
經過打印咱們能獲得1005
,說明commodity已經具有了id,這就是回填的效果。 在這裏,系統默認的方式是給主鍵值加1,若是咱們想要定義本身的主鍵生成方式,可使用selectKey進行自定義:
<insert id="insertCommodity" useGeneratedKeys="true"
keyProperty="id">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select if (max(id) is null, 1, max(id) + 2) as newId from commodity
</selectKey>
insert into commodity (name,price,description)
values (#{name},#{price},#{description})
</insert>
複製代碼
這裏咱們定義主鍵值是最大id加2,若是尚未記錄,則初始化爲1。
update和的delete都會返回影響的條目數 下面僅僅列出配置的實例:
<update id="updateCommodity" parameterType="commodity">
update commodity set
name=#{name},
price=#{price},
description=#{description}
where id=#{id}
</update>
<delete id="deleteCommodity" parameterType="int">
delete from commodity where id=#{id}
</delete>
複製代碼
這一節主要介紹了主要的幾個語句的使用,着重介紹了select語句,同時結合select語句說明了Mybatis中輸入映射和輸出映射的內容,其它一些高級的映射內容,留到後面的文章介紹。