MyBatis的學習(三)——Mapper XML 檔案和parameterType的傳入引數
一、Mapper XML 檔案
Mapper對映檔案是在實際開發過程中使用最多的,也是我們學習的重點。
Mapper檔案中包含的元素有:
- cache – 配置給定名稱空間的快取。
- cache-ref – 從其他名稱空間引用快取配置。
- resultMap – 映射覆雜的結果物件。
- sql – 可以重用的 SQL 塊,也可以被其他語句引用。
- insert – 對映插入語句
- update – 對映更新語句
- delete – 對映刪除語句
- select – 對映查詢語句
二、CRUD操作
①select
select標籤叫Statement
id,必要屬性,在當前的名稱空間下不能重複,指的就是在dao層介面中的方法
指定輸出型別,resultType,值的就是返回的型別
parameterType (不是必須)如果不指定,自動識別,指的就是傳入的引數
別名問題:
資料庫欄位型別--->程式中屬性型別對應關係
②insert
③如何獲得到自增id
useGeneratedKeys:開啟自增長對映
keyProperty:指定id所對應物件中的屬性名
當執行完saveUser()方法後,其返回值依然是執行sql影響的行數,並不是要獲取的自增ID!Mybatis會自動將返回的主鍵值賦值給物件User的屬性id,因此可以通過屬性的get方法獲得插入的主鍵值: System.out.println(User.getId());
另外一種寫法:
在插入操作完成之前或之後,可以配置<selectKey>標籤獲得生成的主鍵的值,獲得插入之前還是之後的值,可以通過配置order屬性來指定。
LAST_INSERT_ID:該函式是mysql的函式,獲取自增主鍵的ID,它必須配合insert語句一起使用
<!-- 增刪改返回的都是int值 不用寫返回值 --> <insert id="addUser" parameterType="User"> <selectKey keyProperty="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO USER VALUES (null,#{name},#{time},#{address}) </insert>
這裡因為使用的MySql資料庫,所以配置的order是after,如果使用的是Oracle資料庫,就該配置成before,這是因為MySql和Oracle生成主鍵不一樣的原因
④update
⑤delete
⑥#和$區別(面試題)
在對映檔案配置<select>標籤執行查詢操作。
注意:
- {}:相當於佔位符
{id}:其中的id可以表示輸入引數的名稱,如果是簡單型別名稱可以任意
- ${}:表示拼接sql語句
- ${value}:表示輸入引數的名稱,如果引數是簡單型別,引數名稱必須是value
<!--
根據id查詢使用者,User findById(int id)
select:配置查詢語句
id:可以通過id找到執行的statement,statement唯一標識
parameterType:輸入引數型別
resultType:輸出結果型別
#{}:相當於佔位符
#{id}:其中的id可以表示輸入引數的名稱,如果是簡單型別名稱可以任意
-->
<select id="getById" parameterType="int" resultType="User" >
select * from user where id=#{id}
</select>
<!--
根據使用者名稱稱來模糊查詢使用者資訊列表;
${}:表示拼接sql語句
${value}:表示輸入引數的名稱,如果引數是簡單型別,引數名稱必須是value
-->
<select id="findByUsername" parameterType="java.lang.String"
resultType="User">
select * from user where username like '%${value}%'
</select>
在Mybatis的mapper中,引數傳遞有2種方式,一種是#{}另一種是${},兩者有著很大的區別:
#{} 實現的是sql語句的預處理引數,之後執行sql中用?號代替,使用時不需要關注資料型別,Mybatis自動實現資料型別的轉換。並且可以防止SQL注入。 preparestament
${} 實現是sql語句的直接拼接,不做資料型別轉換,需要自行判斷資料型別。不能防止SQL注入。
總結:
#{} 佔位符,用於引數傳遞。?佔位
${}用於SQL拼接。 直接拼接在SQL語句中 有注入問題!如果是字串 value
比如模糊查詢
三、parameterType的傳入引數
傳入型別有三種:
1、簡單型別,string、long、integer等
2、Pojo型別,User等
3、HashMap型別。
①傳入型別是HashMap型別
查詢需求:
<select id="getUsers" parameterType="map" resultType="User">
select * from user where birthday between #{startdate} and #{enddate}
</select>
查詢測試:
@Test
public void test7(){
HashMap<String, Object> map=new HashMap<String, Object>();
map.put("startdate", "2018-09-07");
map.put("enddate", "2018-09-25");
List<User> users = mapper.getUsers(map);
for (User user : users) {
System.out.println(user);
}
}
注意:map的key要和sql中的佔位符保持名字一致
②分頁查詢
查詢需求:
<!-- 分頁:map傳參 -->
<select id="selectAuthorByPage" resultType="User">
SELECT * FROM USER LIMIT #{offset}, #{pagesize}
</select>
介面:
List<User> selectAuthorByPage(Map<String, Object> paramList);
測試:
@Test
public void testSelectAuthorByPage() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("offset", 0);
map.put("pagesize", 2);
List<User> authorList = mapper.selectAuthorByPage(map);
for (int i = 0; i < authorList.size(); i++) {
System.out.println(authorList.get(i));
}
}
分頁查詢使用註解傳入:
mapper檔案中的引數佔位符的名字一定要和介面中引數的註解保持一致
<!-- 分頁:map傳參 -->
<select id="selectUserByPage2" resultType="User">
SELECT * FROM USER LIMIT #{offset}, #{pagesize}
</select>
介面:
List<User> selectUserByPage2(@Param(value = "offset") int offset, @Param(value = "pagesize") int pagesize);
測試:
@Test
public void testSelectAuthorByPage2() {
List<User> authorList = mapper.selectUserByPage2(0, 2);
for (int i = 0; i < authorList.size(); i++) {
System.out.println(authorList.get(i));
System.out.println("----------------------");
}
}
分頁查詢使用引數順序:
<!-- 分頁:傳參順序 -->
<select id="selectUserByPage3" parameterType="map" resultType="User">
SELECT * FROM USER LIMIT #{param1},#{param2}
</select>
介面:
List<User> selectUserByPage3(int offset, int pagesize);
測試:
@Test
public void testSelectAuthorByPage3() {
List<User> users = mapper.selectUserByPage3(1, 1);
for (int i = 0; i < users.size(); i++) {
System.out.println(users.get(i));
System.out.println("----------------------");
}
}
四、返回Map型別查詢結果
Mybatis中查詢結果集為Map的功能,只需要重寫ResultHandler介面,,然後用SqlSession 的select方法,將xml裡面的對映檔案的返回值配置成 HashMap 就可以了。具體過程如下
xml配置
<resultMap id="resultMap1" type="HashMap">
<result property="AA" column="r1" />
<result property="BB" column="r2" />
</resultMap>
<select id="getResult" resultMap="resultMap1">
select count(*) r1, max(birthday) r2 from user
</select>
介面:
public HashMap<String, Object> getResult();
測試:
@Test
public void test8(){
HashMap<String, Object> result = mapper.getResult();
System.out.println(result);
}
返回多個值:
<select id="getResult" resultType="map">
select count(*) r1, max(birthday) r2,min(id) r3 from user
</select>
五、解決資料庫欄位和實體類屬性不同
在平時的開發中,我們表中的欄位名和表對應實體類的屬性名稱不一定都是完全相同的,下面來演示一下這種情況下的如何解決欄位名與實體類屬性名不相同的衝突。
上面的測試程式碼演示當實體類中的屬性名和表中的欄位名不一致時,使用MyBatis進行查詢操作時無法查詢出相應的結果的問題以及針對問題採用的兩種辦法:
解決辦法一: 通過在查詢的sql語句中定義欄位名的別名,讓欄位名的別名和實體類的屬性名一致,這樣就可以表的欄位名和實體類的屬性名一一對應上了,這種方式是通過在sql語句中定義別名來解決欄位名和屬性名的對映關係的。
解決辦法二: 通過<resultMap>來對映欄位名和實體類屬性名的一一對應關係。這種方式是使用MyBatis提供的解決方式來解決欄位名和屬性名的對映關係的。
六、MyBatis整體架構
Mybatis是一個類似於Hibernate的ORM持久化框架,支援普通SQL查詢,儲存過程以及高階對映。Mybatis通過使用簡單的XML或註解用於配置和原始對映,將介面和POJO物件對映成資料庫中的記錄。
由於Mybatis是直接基於JDBC做了簡單的對映包裝,所以從效能角度來看:
JDBC > Mybatis > Hibernate
1、配置2類配置檔案,其中一類是:Mybatis-Config.xml (名字不是寫死,隨便定義),另一類:Mapper.xml(多個),定義了sql片段;
2、通過配置檔案得到SqlSessionFactory
3、通過SqlSessionFactory得到SqlSession(操作資料庫)
4、通過底層的Executor(執行器)執行sql,Mybatis提供了2種實現,一種是基本實現,另一種帶有快取功能的實現;