MyBatis 返回結果

LZC發表於2020-02-21

自動對映

MyBatis 會獲取結果中返回的列名並在 Java 類中查詢相同名字的屬性(忽略大小寫)。 這意味著如果發現了資料庫中的 ID 列和Java類中的 id 屬性,MyBatis 會將列 ID 的值賦給 id 屬性。

通常資料庫列使用大寫字母組成的單詞命名,單詞間用下劃線分隔;而 Java 屬性一般遵循駝峰命名法約定。為了在這兩種命名方式之間啟用自動對映,需要將mapUnderscoreToCamelCase 設定為 true。

<settings>
    <!--開啟自動駝峰命名規則對映, 如果資料庫欄位為user_email, MyBatis會自動將其對映到Javabean中的userEmail屬性-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

resultType

透過resultType設定返回結果型別,基本資料型別與POJO類似,下面只演示POJO。

返回單個或者多個

  1. 透過username查詢單個使用者

介面定義如下

public User getUserByUserName(String userName);

介面對應的 Mapper.xml 定義如下所示

<select id="getUserByUserName"
        parameterType="String"
        resultType="com.example.mybatis.entity.User">
    select
    id, username, user_email userEmail, user_city userCity, age
    from user
    where username = #{username}
</select>
  1. 透過username查詢多個使用者

介面定義如下

public List<User> getUserListByUserName(String userName);

介面對應的 Mapper.xml 定義如下所示

<select id="getUserListByUserName"
        parameterType="String"
        resultType="com.example.mybatis.entity.User">
    select
    id, username, user_email userEmail, user_city userCity, age
    from user
    where username = #{username}
</select>

有時候需要將返回的List封裝在一個Map裡面,並使用實體類的某個欄位作為Map的key

介面定義如下

@MapKey("id")
public Map<String, User> getUserListByUserName(String userName);

介面對應的 Mapper.xml 定義如下所示

<select id="getUserListByUserName"
        parameterType="String"
        resultType="map">
    select
    id, username, user_email userEmail, user_city userCity, age
    from user
    where username = #{username}
</select>

resultMap

有時候透過駝峰命名規則並不能對映到我們想要的JavaBean屬性,就可以使用resultMap來實現高階結果集對映。

比如有一張user表裡面有id、user_email、user_city這三個欄位,有一個userVO實體類有如下幾個屬性

public class UserVO {
    private Integer id;
    private String email;
    private String city;
    // 省略get、set方法
}

現在需要使用MyBatis將user資訊查詢出來並對映到userVO實體類

介面定義如下

public UserVO getUserInfoById(Integer id);

介面對應的 Mapper.xml 定義如下所示

<resultMap id="userVO" type="com.example.mybatis.entity.UserVO">
    <!--
        指定主鍵類的封裝規則
        id定義主鍵,底層會有一些最佳化
        column指定資料路的列
        property指定對應的JavaBean屬性
        -->
    <id column="id" property="id" />
    <!--定義普通列的封裝-->
    <result column="user_email" property="email" />
    <result column="user_city" property="city" />
</resultMap>
<select id="getUserInfoById" resultMap="userVO">
    select * from user where id = #{id}
</select>

多表關聯查詢

實際開發中不可能只是對單表進行操作,一定會涉及到多表關聯查詢,資料表之間的關係有三種:一對一關係、一對多關係、多對多關係。

一對一

一個學生對應一個班級,而一個班級可以對應多個學生。

CREATE TABLE `t_classes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `t_student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(11) DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `cid` (`cid`),
  CONSTRAINT `student_ibfk` FOREIGN KEY (`cid`) REFERENCES `t_classes` (`id`)
);

實體類

public class Classes {
    private Integer id;
    private String name;
    private List<Student> students;
}

public class Student {
    private Integer id;
    private String name;
    private Classes classes;
}

透過學生id查詢學生資訊,並且把學生班級資訊一起查詢出來。

介面定義如下

public Student getStudentById(Integer id);

介面對應的 Mapper.xml 定義如下所示

<resultMap id="studentResultMap" type="Student">
    <id column="sid" property="id" />
    <result column="sname" property="name" />
    <!-- 對映 classes 屬性 -->
    <association property="classes" javaType="com.example.mybatis.entity.Classes">
        <id column="cid" property="id" />
        <result column="cname" property="name" />
    </association>
</resultMap>
<select id="getStudentById" resultMap="studentResultMap">
    select s.id sid,s.name sname, c.id cid, c.name cname
    from t_student s , t_classes c
    where s.cid = c.id
    and s.id = #{id}
</select>

將上面的查詢語句修改為分步查詢、延遲查詢

<resultMap id="studentResultMap" type="com.example.mybatis.entity.Student">
    <id column="id" property="id" />
    <result column="name" property="name" />
    <!--
        對映 classes 屬性
        property: 對映到JavaBean中的屬性
        column: 指定某個列的值傳遞到 select 中的方法
        select: 表名當前屬性是呼叫select指定的方法查出的結果
                如果是呼叫當前mapper中的方法, 則直接填寫要呼叫方法的id就行了
                如果是呼叫其它mapper中的方法, 則需要這樣填寫com.xxx.mapper.XxxMapper.getClassesById
        fetchType: lazy-> 懶載入、eager-> 全部載入, 
        如果設定了懶載入模式, 那麼當獲取classes屬性時才會從資料庫中載入classes資料出來
        javaType: 對映實體類
        -->
    <association property="classes"
                 column="cid"
                 select="getClassesById"
                 javaType="com.example.mybatis.entity.Classes"
                 fetchType="lazy">
        <id column="id" property="id" />
        <result column="name" property="name" />
    </association>
</resultMap>
<select id="getStudentById" resultMap="studentResultMap">
    select s.id,s.name,s.cid
    from t_student s
    where s.id = #{id}
</select>
<select id="getClassesById" resultType="com.example.mybatis.entity.Classes">
    select c.id,c.name from t_classes c where c.id = #{id}
</select>

一對多

現在反過來查詢 Classes,將級聯的所有 Student 一併查詢。

介面定義如下

public Classes getClassesById(Integer id);

介面對應的 Mapper.xml 定義如下所示

<resultMap id="classesResultMap" type="com.example.mybatis.entity.Classes">
    <id column="cid" property="id" />
    <result column="cname" property="name" />
    <collection property="students" ofType="com.example.mybatis.entity.Student">
        <id column="sid" property="id" />
        <result column="sname" property="name"/>
    </collection>
</resultMap>
<select id="getClassesById" resultMap="classesResultMap">
    select s.id sid,s.name sname, c.id cid, c.name cname
    from t_student s , t_classes c
    where s.cid = c.id
    and c.id = #{id}
</select>

需要注意的是 association 標籤,透過設定 javaType 屬性,對映實體類,collection 標籤,透過設定 ofType 屬性對映實體類。

將上面查詢修改成分步查詢、延遲查詢

<resultMap id="classesResultMap" type="com.example.mybatis.entity.Classes">
    <id column="cid" property="id" />
    <result column="cname" property="name" />
    <!--
            這裡的column只傳遞了一個欄位,如果想傳入多個欄位可以這樣寫
            column="{key1=column1, key2=column2}"
            相當於封裝成了一個Map, 當前查詢可以這樣寫column="{id=cid}"
        -->
    <collection
                fetchType="lazy"
                property="students"
                select="getStudentByClassesId"
                column="cid">
    </collection>
</resultMap>
<select id="getClassesById" resultMap="classesResultMap">
    select c.id cid, c.name cname
    from t_classes c
    where c.id = #{id}
</select>
<select id="getStudentByClassesId" resultType="com.example.mybatis.entity.Student">
    select s.id , s.name from t_student s where s.cid = #{id}
</select>

多對多

多對多其實是雙向的一對多關係,所以雙方都是用 collection 標籤設定級聯,與上面的一對多是類似的。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章