1. 程式人生 > >MyBatis框架的學習(四)——Mapper.xml檔案中的輸入和輸出對映以及動態sql

MyBatis框架的學習(四)——Mapper.xml檔案中的輸入和輸出對映以及動態sql

前面對MyBatis框架的學習中,我們對Mapper.xml對映檔案多少有些瞭解。本文將對Mapper.xml對映檔案作更加細緻的梳理,首先從Mapper.xml檔案中的輸入和輸出對映開始。本文案例程式碼的編寫是建立在前文MyBatis框架的學習(三)——Dao層開發方法案例基礎之上的!

輸入對映和輸出對映

Mapper.xml對映檔案中定義了操作資料庫的sql,每個sql是一個statement,對映檔案是mybatis的核心。

parameterType(輸入型別)

傳遞簡單型別

傳遞簡單型別,我之前已講過,這裡只給出案例,如下:
這裡寫圖片描述

傳遞pojo物件

MyBatis使用ognl表示式解析物件欄位的值,#{}或者${}括號中的值為pojo屬性名稱。傳遞pojo物件之前也已講過,這裡同樣只給出案例,如下:
這裡寫圖片描述

傳遞pojo包裝物件

開發中通過pojo傳遞查詢條件,查詢條件是綜合的查詢條件,不僅包括使用者查詢條件還包括其它的查詢條件(比如將使用者購買商品資訊也作為查詢條件),這時可以使用包裝物件傳遞輸入引數。即pojo類中包含pojo類。
例如這樣一個需求:根據使用者id查詢使用者資訊,查詢條件放到QueryVo類的user屬性中。有需求,就要解決它。我們可在cn.itheima.mybatis.po包下新建一個QueryVo類,如下:

public class QueryVo {

    private User user;

    public User getUser() {
        return
user; } public void setUser(User user) { this.user = user; } }

接下來我們就要在UserMapper.xml對映檔案中編寫sql語句了,即在UserMapper.xml對映檔案中新增如下配置資訊:

<select id="getUserByQueryVo" parameterType="queryvo" resultType="user">
    select * from user where id=#{user.id};
</select>

使用包裝型別查詢使用者時,可使用ognl從物件中取屬性值,並且如果是包裝物件可以使用.

操作符來取內容的屬性。
然後在UserMapper介面中新增如下方法:

User getUserByQueryVo(QueryVo queryVo);

最後在UserMapperTest單元測試類編寫如下測試方法:

@Test
public void testGetUserByQueryVo() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 獲得mapper代理物件
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 建立一個QueryVo物件
    QueryVo queryVo = new QueryVo();
    User user = new User();
    user.setId(10);
    queryVo.setUser(user);
    // 執行查詢
    User result = userMapper.getUserByQueryVo(queryVo);
    System.out.println(result);
    sqlSession.close();
}

傳遞HashMap

傳遞HashMap在實際開發中用的很少,但我還是要講一下。以例明示——傳遞HashMap綜合查詢使用者資訊,在UserMapper.xml對映檔案中新增如下配置資訊:

<!-- 傳遞HashMap綜合查詢使用者資訊 -->
<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
   select * from user where id=#{id} and username like '%${username}%'
</select>

上面的id和username是HashMap的key。
接著在UserMapper介面中新增如下方法:

User findUserByHashmap(HashMap<String, Object> map);

最後在UserMapperTest單元測試類編寫如下測試方法:

@Test
public void testFindUserByHashmap() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 獲得mapper代理物件
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 構造查詢條件Hashmap物件
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("id", 30);
    map.put("username", "趙雲");
    // 執行查詢
    User result = userMapper.findUserByHashmap(map);
    System.out.println(result);
    sqlSession.close();
}

resultType(輸出型別)

輸出簡單型別

有這樣一個需求:查詢使用者表中的記錄數。有需求就要解決它,我們首先在UserMapper.xml對映檔案中新增如下配置資訊:

<!-- 查詢使用者表中的記錄數 -->
<select id="getUserCount" resultType="int">
    SELECT COUNT(*) FROM `user`
</select>

接著在UserMapper介面中新增如下方法:

Integer getUserCount();

最後在UserMapperTest單元測試類編寫如下測試方法:

@Test
public void testGetUserCount() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 獲得mapper代理物件
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 執行查詢
    int count = userMapper.getUserCount();
    System.out.println(count);
    sqlSession.close();
}

輸出簡單型別必須查詢出來的結果集只有一條記錄,最終將第一個欄位的值轉換為輸出型別。

輸出pojo物件

輸出pojo物件,我之前已講過,這裡只給出案例,如下:
這裡寫圖片描述

輸出pojo列表

輸出pojo列表,我之前同樣已講過,這裡只給出案例,如下:
這裡寫圖片描述
這兒再給出一個案例——查詢訂單的所有資訊。我們mybatis資料庫中已經有了訂單表(orders表)了,如下:
這裡寫圖片描述
大家可能想到不會想,就會像下面這樣做。首先在cn.itheima.mybatis.po包下新建一個Orders類:

public class Orders {
    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number == null ? null : number.trim();
    }

    public Date getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note == null ? null : note.trim();
    }

}

然後在cn.itheima.mybatis.mapper包下建立一個OrderMapper.xml對映檔案,其內容為:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itheima.mybatis.mapper.OrderMapper">
    <select id="getOrderList" resultType="orders">
        select * from orders;
    </select>
</mapper>

緊接著在cn.itheima.mybatis.mapper包下建立一個OrderMapper介面:

public interface OrderMapper {
    List<Orders> getOrderList();
}

最後建立OrderMapper介面的單元測試類——OrderMapperTest.java,修改OrderMapperTest類的內容為:

public class OrderMapperTest {

    private SqlSessionFactory sqlSessionFactory = null; // 工廠物件一般在我們的系統中是單例的

    @Before
    public void init() throws IOException {
        // 第一步,建立SqlSessionFactoryBuilder物件
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 第二步,載入配置檔案
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 第三步,建立SqlSessionFactory物件
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }

    @Test
    public void testGetOrderList() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        List<Orders> orderList = orderMapper.getOrderList();
        for (Orders orders : orderList) {
            System.out.println(orders);
        }
        sqlSession.close();
    }

}

在testGetOrderList方法中的以下程式碼處打一個斷點:

for (Orders orders : orderList) {

然後以Debug模式執行該方法,可發現查詢出來的每一個Orders物件中的userId屬性值都為null,如下:
這裡寫圖片描述
很明顯這並不是我們所想要的結果。為了達到我們預期的效果,可為user_id列加別名,即將OrderMapper.xml對映檔案中id為getOrderList的select元素修改為:

<select id="getOrderList" resultType="orders">
    select id,user_id userId,number,createtime,note from orders;
</select>

只要你返回的結果的列名和pojo中的屬性一致,就可以自動映射了。
這樣當我們再次以Debug模式執行testGetOrderList方法,就能達到我們預期的結果了,如下:
這裡寫圖片描述
這種方式比較簡單粗暴,其實要達到我們所預期的效果,還有另一種方式,那就是使用resultMap這個屬性,下面我就會講到。

resultMap

resultMap可以指定pojo將查詢結果對映為pojo,但需要pojo的屬性名和sql查詢的列名一致方可對映成功。如果sql查詢欄位名和pojo的屬性名不一致,可以通過resultMap將欄位名和屬性名作一個對應關係 ,resultMap實質上還需要將查詢結果對映到pojo物件中。
resultMap可以實現將查詢結果對映為複雜型別的pojo,比如在查詢結果對映物件中包括pojo和list實現一對一查詢和一對多查詢。
現在我就來實現查詢訂單所有資訊的需求,而不是像上面那樣簡單粗暴地給user_id列加別名。首先在OrderMapper.xml對映檔案中新增如下<select>元素:

<select id="getOrderListResultMap" resultMap="order_list_result_map">
    select id,user_id,number,createtime,note from orders;
</select>

使用resultMap指定上邊定義的order_list_result_map。
接著定義resultMap。由於上邊的OrderMapper.xml對映檔案中sql查詢列和Orders.java類屬性不一致,因此需要定義resultMap:order_list_result_map將sql查詢列和Orders.java類屬性對應起來。

<resultMap type="orders" id="order_list_result_map">
    <!-- id是主鍵的對映,其中property是pojo中主鍵的屬性,column是返回結果中主鍵的列 -->
    <id property="id" column="id" />
    <!-- 普通列使用result對映 -->
    <result property="userId" column="user_id" />
    <result property="number" column="number" />
    <result property="createtime" column="createtime" />
    <result property="note" column="note" />
</resultMap>
  • type:指resultMap要對映成的資料型別(返回結果對映的pojo,可以使用別名)。
  • <id />:此屬性表示查詢結果集的唯一標識,非常重要。如果是多個欄位為複合唯一約束則定義多個<id />
  • property:表示Orders類的屬性。
  • column:表示sql查詢出來的欄位名。
    column和property放在一塊兒表示將sql查詢出來的欄位對映到指定的pojo類屬性上。
  • <result />:普通列使用result標籤對映。

然後在OrderMapper介面新增如下方法:

List<Orders> getOrderListResultMap();

最後在OrderMapperTest單元測試類中新增如下測試方法:

@Test
public void testGetOrderListResultMap() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<Orders> orderList = orderMapper.getOrderListResultMap();
    for (Orders orders : orderList) {
        System.out.println(orders);
    }
    sqlSession.close();
}

同樣在testGetOrderListResultMap方法中的以下程式碼處打一個斷點:

for (Orders orders : orderList) {

然後以Debug模式執行該方法,可發現查詢出來的每一個Orders物件中的userId屬性都有值了。

動態sql

我們可通過mybatis提供的各種標籤方法實現動態拼接sql。

if

現有這樣一個需求:傳遞pojo類綜合查詢使用者資訊,更具體地說就是我們使用使用者的id和username能更加靈活地查詢使用者資訊。
為了解決這個需求,我們就要使用<if>標籤了。首先在UserMapper.xml對映檔案中新增如下<select>元素:

<select id="findUserList" parameterType="user" resultType="user">
    select * from user
    where 1=1
    <if test="id!=null">
        and id=#{id}
    </if>
    <if test="username!=null and username!=''">
        and username like '%${username}%'
    </if>
</select>

注意:

  1. username要做不等於空字串的校驗。
  2. User類中id屬性的型別要改為Integer包裝型別,因為int型別的id是不可能為null的!

然後在UserMapper介面新增如下方法:

List<User> findUserList(User user);

最後在UserMapperTest單元測試類中新增如下測試方法:

@Test
public void testFindUserList() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 獲得mapper代理物件
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 設定查詢條件
    User user = new User();
    // user.setId(10);
    user.setUsername("張");
    // 執行查詢
    List<User> userList = userMapper.findUserList(user);
    for (User user2 : userList) {
        System.out.println(user2);
    }
    sqlSession.close();
}

讀者可試著給User物件只為id屬性賦值,或者只為username屬性賦值,又或者兩者同時賦值。

where

UserMapper.xml對映檔案中如下<select>元素:

<select id="findUserList" parameterType="user" resultType="user">
    select * from user
    where 1=1
    <if test="id!=null">
        and id=#{id}
    </if>
    <if test="username!=null and username!=''">
        and username like '%${username}%'
    </if>
</select>

也可使用<where>標籤寫為:

<select id="findUserList" parameterType="user" resultType="user">
    select * from user
    <where>
        <if test="id!=null">
            and id=#{id}
        </if>
        <if test="username != null and username != ''">
            and username like '%${username}%'
        </if>
    </where>
</select>

<where />可以自動處理第一個and。

foreach

現有這樣一個需求:傳入多個id查詢使用者資訊。如若編寫sql語句,可用下邊兩個sql實現:

  1. SELECT * FROM USER WHERE username LIKE '%張%' AND (id =10 OR id =89 OR id=16)
  2. SELECT * FROM USER WHERE username LIKE '%張%' id IN (10,89,16)

為了解決這個需求,首先在QueryVo類中定義List屬性ids儲存多個使用者id,並新增getter/setter方法,如下:

public class QueryVo {

    private User user;
    private List<Integer> ids;

    public List<Integer> getIds() {
        return ids;
    }

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

}

然後在UserMapper.xml對映檔案中新增如下<select>元素:

<!-- 動態sql foreach測試 -->
<select id="findUserByIds" parameterType="queryvo" resultType="user">
    SELECT * FROM `user` 
    <where>
        <!-- and id IN(1,10,20,21,31) -->
        <foreach collection="ids" item="id" open="and id in(" close=")" separator=",">
            #{id}
        </foreach>
    </where>
</select>

向sql中傳遞陣列或List,mybatis將使用foreach解析。
接著在UserMapper介面新增如下方法:

List<User> findUserByIds(QueryVo queryVo);

最後在UserMapperTest單元測試類中新增如下測試方法:

@Test
public void testFindUserByIds() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 獲得mapper代理物件
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 設定查詢條件
    QueryVo queryVo = new QueryVo();
    List<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(10);
    ids.add(16);
    ids.add(22);
    queryVo.setIds(ids);
    // 執行查詢
    List<User> userList = userMapper.findUserByIds(queryVo);
    for (User user2 : userList) {
        System.out.println(user2);
    }
    sqlSession.close();
}

sql片段

sql中可將重複的sql提取出來,使用時用include引用即可,最終達到sql重用的目的,如下:

<select id="findUserList" parameterType="user" resultType="user">
    select * from user
    <where>
        <if test="id!=null">
            and id=#{id}
        </if>
        <if test="username != null and username != ''">
            and username like '%${username}%'
        </if>
    </where>
</select>

將where條件抽取出來,同時我們也可將要查詢的欄位抽取出來。

<sql id="find_user_list_where">
    <where>
        <if test="id!=null">
            and id=#{id}
        </if>
        <if test="username != null and username != ''">
            and username like '%${username}%'
        </if>
    </where>
</sql>

<sql id="user_field_list">
    id,username,birthday,sex,address
</sql>

使用include引用:

<select id="findUserList" parameterType="user" resultType="user">
    select <include refid="user_field_list"/> from user
    <include refid="find_user_list_where"/>
</select>

注意:如果引用其它mapper.xml對映檔案的sql片段,則在引用時需要加上namespace,如下:

<include refid="namespace.sql片段"/>

相關推薦

MyBatis框架學習()——Mapper.xml檔案輸入輸出對映以及動態sql

前面對MyBatis框架的學習中,我們對Mapper.xml對映檔案多少有些瞭解。本文將對Mapper.xml對映檔案作更加細緻的梳理,首先從Mapper.xml檔案中的輸入和輸出對映開始。本文案例程式碼的編寫是建立在前文MyBatis框架的學習(三)——Dao

mybatis學習筆記之——mybatisMapper XML檔案select元素

select元素: Select元素用來定義查詢操作,常用屬性如下。 id:唯一識別符號。用來引用這條語句,需要和介面的方法名一致。 parameterType:將會傳入這條語句的引數類的完全限定名或別名。這個屬性是可選的,因為 MyBatis 可以通過 TypeHandler 推斷出具

mybatis學習筆記之——mybatisMapper XML檔案resultMap屬性

resultMap resultMap:自定義結果集對映規則,自定義某個JavaBean的封裝規則。 id:唯一id,方便引用。 type:自定義規則的Java類。 具體其他屬性詳細資訊和配置程式碼如下: <resultMap id="MyEmp" type="com.te

mybatis框架mapper.xml檔案sql的使用方法:

1.<!-- 根據id查詢 --> <select id="getFileInfo" parameterType="java.lang.String" resultMap="testFileBean">select * from test_tb_info where 1=1 <i

Mybatismapper.xml檔案插入資料返回自增主鍵

使用MyBatis往MySQL資料庫中插入一條記錄後,返回該條記錄的自增主鍵值。Mapper檔案應該怎麼寫呢? Mybatis的Mapper的標籤中有一個屬性,我們一起來看看: useGenerateKeys這個屬性,意思就是使用自增。我們需要將這個欄位設定為 true 。 同時,還需

Mybatismapper.xml檔案重要註解說明

#{}和${}的區別及使用參考: Mybatis中#{}和${}的區別以及對sql注入、預編譯、jdbcType的說明 Mybatis方法各種情況的傳參和取參參考:Mybatis的處理引數原始碼分析和方法傳參取參分析 1、<mapper> namespace:名稱空間;指定為

mybatis MyBatis Mapper.xml檔案 $#的區別

1.  MyBatis Mapper.xml檔案中 $和#的區別   網上有很多,總之,簡略的寫一下,作為備忘。例子中假設引數名為 paramName,型別為 VARCHAR 。 1.優先使用#{paramName,jdbcType=VARCHAR} 寫法,

使用mybatisMapper.xml檔案如何判斷多個引數不為空null

第一種:使用where標籤 <select id="***" resultMap="BaseResultMap" parameterType="java.util.Map">select

mybatis mapper.xml檔案$#的使用區別

#{}表示一個佔位符即?,可以有效防止sql注入。在使用時不需要關心引數值的型別,mybatis會自動進行java型別和jdbc型別的轉換。 #{}可以接收簡單型別值或pojo屬性值,如果傳入簡單型別值,#{}括號中可以是任意名稱。 <!-- 根據名稱

MyBatis框架淺析之 Mapper.xml 映射文件

多個 基本類 之前 簡單 pri 處理 before lang provide Mapper XML 文件 MyBatis 的真正強大在於它的映射語句,也是它的魔力所在。由於它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進行對比

mybaitis 的 mapper.xml 檔案 引數為List集合SQL 的寫法。

1、應用場景: 傳參: MaterialCodeList, activity_end_time,userCode 具體SQl: <if test> 的驗證: "MaterialCodeList != null and MaterialCodeList.size()>0"

mapper.xml檔案獲取最新插入資料的主鍵

在開發過程中,我們常常用到在插入資料時,需要得到剛插入的資料的主鍵,MySQL中有以下做法: 1、推薦使用 <insert id="addVehicleParam" parameterType="com.corp.dto.VehicleParamAddDt

mapper.xml檔案標籤沒有提示的解決

1、首先我們來看看mapper.xml的標頭檔案 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.

mybatis熱部署載入*Mapper.xml檔案,手動重新整理*Mapper.xml檔案

由於專案已經發布到線上,要是修改一個Mapper.xml檔案的話,需要重啟整個服務,這個是很耗時間的,而且在一段時間內導致服務不可用,嚴重影響使用者 的體驗度。所以希望可以有一個機制可以,當修改某個mapper.xml的時候,只要重新載入這個mapper.xml就好了,

MyBatis超詳細介紹——Mapper XML檔案

MyBatis Mapper XML檔案 (本文作為學習筆記,瞭解更多請參考:MyBatis參考文件) 頂級元素介紹(按照應該被定義的順序) cache – 給定名稱空間的快取配置。 cac

Mapper.xml檔案如何判斷多個引數不為空null

第一種:使用where標籤 <select id="***" resultMap="BaseResultMap" parameterType="java.util.Map">select t.* from 表名 t<where><if test=" 傳進來的欄位 != null

web.xml檔案配置的區別

web工程大多都需要配置web.xml檔案,web.xml檔案主要用來配置Listener、Filter、Servlet等。web.xml檔案包括xml檔案頭,DOCTYPE宣告,web-app元素。 web.xml的載入過程(引用) 在web-app元素內,元素的配置順

關於IDEA專案pom.xml檔案jar報錯,以及maven在IDEA的配置!!!

這是第一次自己寫部落格,兩天時間通過查詢資料,也算掌握了IDEA中maven的使用。 畢竟我是一個健忘的人,所以記錄下來。 <-----------------------------------------------------------華麗的分割線-----

MyBatis學習總結三——輸入對映輸出對映以及多表關聯查詢

關於MyBatis的輸入對映和輸出對映,可輸入的型別很多,輸出型別亦是如此。如圖所示: 一、輸入型別是通過引數parameterType來設定的,引數型別有基本資料型別、包裝型別pojo、Map 基礎型別(String,int,long,double...) pojo型別

使用dom4j對xml檔案進行讀取輸出操作

1.xml檔案的讀取     讀取xml檔案的方式有兩種,一種是面向模型的DOM方式,一種是面向事件的SAX方式     DOM方式原理:一次性的將xml文件加入記憶體,在記憶體中形成一顆dom樹,然後通過語言對樹的節點進行操作。    顯然這種操作查詢元素快,但