1. 程式人生 > >通過XML、註解配置MyBatis SQL對映器

通過XML、註解配置MyBatis SQL對映器

SpringBoot配置MyBatis在 SpringBoot整合MyBatis開發 這篇文章中已經描述了,這篇文章主要講解一些SQL對映器中的寫法及常用標籤。

定義xml對映檔案

<mapper namespace="com.test.springboot.mybatis.dao.UserMapper">

    <resultMap id="AddressResultMap" type="com.test.springboot.mybatis.bean.AddressPo">
        <id column="address_id" jdbcType="INTEGER"
property="id" /> <result column="address" jdbcType="VARCHAR" property="address" /> <result column="user_id" jdbcType="VARCHAR" property="user_id" /> </resultMap> <resultMap id="UserResultMap" type="com.test.springboot.mybatis.bean.UserPo"> <id
column="id" jdbcType="VARCHAR" property="id" /> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="password" jdbcType="VARCHAR" property="password" /> <result column="realname" jdbcType="VARCHAR" property="realname" /> <result
column="company" jdbcType="VARCHAR" property="company" /> <result column="job" jdbcType="VARCHAR" property="job" /> <result column="salt" jdbcType="VARCHAR" property="salt" /> <result column="status" jdbcType="TINYINT" property="status" /> <result column="time" jdbcType="BIGINT" property="time" /> <!-- 一對多對映 --> <collection property="addressList" resultMap="AddressResultMap"/> </resultMap> <sql id="Base_Column_List" > id, username, password, realname, company, job, salt, status, time </sql> <select id="queryList" resultMap="UserResultMap"> SELECT <include refid="Base_Column_List"/> FROM auth_user <where> <if test="username != null"> username = #{username} </if> <if test="job != null"> AND job = #{job} </if> </where> </select> <select id="queryByUsername" resultMap="UserResultMap"> SELECT u.id, u.username as aaa, u.password, u.realname, u.company, u.job, u.salt, u.status, u.time, a.address, a.id as address_id, a.user_id FROM auth_user AS u LEFT JOIN auth_address AS a ON u.id = a.user_id WHERE u.username = #{username} </select> </mapper>

namespace:該標籤用於指定對映器對應的介面檔案,需要寫介面檔案全路徑。

resultMap:使用者設定SQL返回資料儲存欄位資訊。

resultMap.type:用於指定返回資訊對應的實體類。

sql:可編寫一個SQL片段,用於複用到具體的SQL操作中。

select:用作查詢操作的SQL標籤。

MyBatis 不同對映語句例項

INSERT

通過自增長設定主鍵

<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="studId">
    INSERT INTO STUDENTS(NAME, EMAIL, PHONE) VALUES(#{name},#{email},#{phone})
</insert>

針對支援序列生成主鍵值

<insert id="insertStudent" parameterType="Student">
    <selectKey keyProperty="studId" resultType="int" order="BEFORE">
        SELECT ELEARNING.STUD_ID_SEQ.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL, PHONE) VALUES(#{studId},#{name},#{email},#{phone})
</insert>

//使用觸發器  
<insert id="insertStudent" parameterType="Student">
    INSERT INTO STUDENTS(NAME,EMAIL, PHONE) VALUES(#{name},#{email},#{phone})
    <selectKey keyProperty="studId" resultType="int" order="AFTER">
        SELECT ELEARNING.STUD_ID_SEQ.CURRVAL FROM DUAL
    </selectKey>
</insert>

SELECT

<select id="queryList" resultMap="UserResultMap">
    SELECT 
        <include refid="Base_Column_List"/>
    FROM auth_user
    <where>
        <if test="username != null">
            username = #{username}
        </if>
        <if test="job != null">
            AND job = #{job}
        </if>
    </where>
</select>

條件不定查詢,通過where標籤ifchoose等標籤可對欄位進行判斷,看是否需要新增到where條件中進行查詢。

    <select id="queryByUsername" resultMap="UserResultMap">
        SELECT
            u.id, u.username as aaa, u.password, u.realname, u.company, u.job, u.salt, u.status, u.time, a.address, a.id as address_id, a.user_id 
        FROM 
            auth_user 
        AS u LEFT JOIN auth_address AS a ON u.id = a.user_id WHERE u.username = #{username}
    </select>

多表聯合查詢,需要在resultMap配置好一對多一對一等關係。SQL返回結果會直接注入到resultMap配置的實體類中。

MyBatis結果集對映規則

  • 對於 List, Collection, Iterable型別,返回 java.util.ArrayList
  • 對於Map 型別,返回 java.util.HashMap
  • 對於Set 型別: 返回 java.util.HashSet
  • 對於SortedSet型別: 返回java.util.TreeSet

MyBatis 對映關係

一對一對映

方式1: 使用點語法進行對映

public class Student {
   private Integer studId;
   private String name;
   private String email;
   private Address address;        //一個地址物件, 每個學生對應一個地址  
}

<resultMap type="Student" id="StudentWithAddressResult">
  <id property="studId" column="stud_id" />
  <result property="name" column="name" />
  <result property="email" column="email" />
  <result property="phone" column="phone" />
  <result property="address.addrId" column="addr_id" />
  <result property="address.street" column="street" />
  <result property="address.city" column="city" />
  <result property="address.state" column="state" />
  <result property="address.zip" column="zip" />
  <result property="address.country" column="country" />
</resultMap>

<select id="selectStudentWithAddress" parameterType="int" resultMap="StudentWithAddressResult">
    SELECT 
        STUD_ID, NAME, EMAIL, A.ADDR_ID, STREET, CITY, STATE, ZIP, COUNTRY
    FROM 
        STUDENTS S LEFT OUTER JOIN ADDRESSES A ON S.ADDR_ID=A.ADDR_ID
    WHERE 
        STUD_ID=#{studId}
</select>

方式2: 使用巢狀結果 ResultMap進行對映

<resultMap type="Address" id="AddressResult">
      <id property="addrId" column="addr_id" />
      <result property="street" column="street" />
      <result property="city" column="city" />
</resultMap>

<resultMap type="Student" id="StudentWithAddressResult">
      <id property="studId" column="stud_id" />
      <result property="name" column="name" />
      <result property="email" column="email" />
      <association property="address" resultMap="AddressResult" />
</resultMap>

<select id="findStudentWithAddress" parameterType="int" resultMap="StudentWithAddressResult">
    SELECT 
        STUD_ID, NAME, EMAIL, A.ADDR_ID, STREET, CITY, STATE, ZIP, COUNTRY
    FROM 
        STUDENTS S LEFT OUTER JOIN ADDRESSES A ON S.ADDR_ID=A.ADDR_ID
    WHERE 
        STUD_ID=#{studId}
</select>

方式3:本身內部巢狀

<resultMap type="Student" id="StudentWithAddressResult">
      <id property="studId" column="stud_id" />
      <result property="name" column="name" />
      <result property="email" column="email" />
      <association property="address" javaType="Address">
            <id property="addrId" column="addr_id" />
            <result property="street" column="street" />
            <result property="city" column="city" />
            <result property="state" column="state" />
            <result property="zip" column="zip" />
            <result property="country" column="country" />
      </association>
</resultMap>

<select id="findStudentWithAddress" parameterType="int" resultMap="StudentWithAddressResult">
    SELECT 
        STUD_ID, NAME, EMAIL, A.ADDR_ID, STREET, CITY, STATE, ZIP, COUNTRY
    FROM 
        STUDENTS S LEFT OUTER JOIN ADDRESSES A ON S.ADDR_ID=A.ADDR_ID
    WHERE 
        STUD_ID=#{studId}
</select>

一對多對映

使用<collection>元素將 一對多型別的結果 對映到 一個物件集合上

使用巢狀物件形式顯示

public class Tutor {
    private Integer tutorId;
    private String name;
    private String email;
    private Address address;
    private List<Course> courses;
    / setters & getters
}

<resultMap type="Tutor" id="TutorResult">
    <id column="tutor_id" property="tutorId" />
    <result column="tutor_name" property="name" />
    <result column="email" property="email" />
    <collection property="courses" resultMap="CourseResult" />
</resultMap>

<select id="findTutorById" parameterType="int" resultMap="TutorResult">
    SELECT 
        T.TUTOR_ID, T.NAME AS TUTOR_NAME, EMAIL, C.COURSE_ID, C.NAME, DESCRIPTION, START_DATE, END_DATE
    FROM 
        TUTORS T LEFT OUTER JOIN ADDRESSES A ON T.ADDR_ID=A.ADDR_ID
    LEFT OUTER JOIN 
        COURSES C ON T.TUTOR_ID=C.TUTOR_ID
    WHERE 
        T.TUTOR_ID=#{tutorId}
</select>

使用巢狀語句實現

<resultMap type="Tutor" id="TutorResult">
    <id column="tutor_id" property="tutorId" />
    <result column="tutor_name" property="name" />
    <result column="email" property="email" />
    <association property="address" resultMap="AddressResult" />
    <collection property="courses" column="tutor_id" select="findCoursesByTutor" />
</resultMap>

<select id="findTutorById" parameterType="int" resultMap="TutorResult">
    SELECT 
        T.TUTOR_ID, T.NAME AS TUTOR_NAME, EMAIL
    FROM TUTORS T WHERE T.TUTOR_ID=#{tutorId}
</select>

<select id="findCoursesByTutor" parameterType="int" resultMap="CourseResult">
  SELECT * FROM COURSES WHERE TUTOR_ID=#{tutorId}
</select>
  • 注意:巢狀 Select 語句查詢會導致 N+1 選擇問題。 首先,主查詢將會執行(1 次),對於主 查詢返回的每一行,另外一個查詢將會被執行(主查詢 N 行,則此查詢 N 次)。對於 大型資料庫而言,這會導致很差的效能問題。

動態SQL

mybatis 提供: <if>,<choose>,<where>,<foreach>,<trim> 進行構造動態SQL

if

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult"></select>
    SELECT * FROM COURSES WHERE TUTOR_ID= #{tutorId}
    <if test="courseName != null">
        AND NAME LIKE #{courseName}
    </if>
</select>

iftest條件成立時, 才會新增if中的內容到SQL語句中。

choose, when, otherwise

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">
    SELECT * FROM COURSES
    <choose>
        <when test="searchBy == 'Tutor'">
            WHERE TUTOR_ID= #{tutorId}
        </when>
        <when test="searchBy == 'CourseName'">
            WHERE name like #{courseName}
        </when>
        <otherwise>
            WHERE TUTOR start_date >= now()
        </otherwise>
    </choose>
</select>

mybatis計算<choose> 測試條件的值,且使用第一個值為true的子句, 如果沒有條件為true,則使用<otherwise>內的子句。

where

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">
    SELECT * FROM COURSES
    <where>
        <if test=" tutorId != null ">
            TUTOR_ID= #{tutorId}
        </if>
        <if test="courseName != null">
            AND name like #{courseName}
        </if>
        <if test="startDate != null">
            AND start_date >= #{startDate}
        </if>
        <if test="endDate != null">
            AND end_date <= #{endDate}
        </if>
    </where>
</select>

trim

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">
     SELECT * FROM COURSES
     <trim prefix="WHERE" prefixOverrides="AND | OR"> 
         <if test=" tutorId != null ">
             TUTOR_ID= #{tutorId}
         </if>  
         <if test="courseName != null">
            AND name like #{courseName}
         </if>
     </trim>
</select>

trim標記是一個格式化的標記,可以完成set或者是where標記的功能。

prefix:字首。

prefixoverride:去掉第一個and或者是or。 

<trim prefix="set" suffixoverride="," suffix=" where id = #{id} ">
    <if test="name != null and name.length()>0"> name=#{name} , </if>
    <if test="gender != null and gender.length()>0"> gender=#{gender} ,  </if>
</trim>

假如說namegender的值都不為null的話列印的SQL為:update user set name='xx' , gender='xx' where id='x'gender後面跟的逗號不會顯示。

suffixoverride:去掉最後一個逗號(也可以是其他的標記,就像是上面字首中的and一樣)

suffix:字尾

foreach

<select id="searchCoursesByTutors" parameterType="map" resultMap="CourseResult">
    SELECT * FROM COURSES
    <if test="tutorIds != null">
        <where>
            <foreach item="tutorId" collection="tutorIds">
                OR tutor_id=#{tutorId}
            </foreach>
        </where>
    </if>
</select>

多個引數操作

使用map形式引入

<select id="findAllStudentsByNameEmail" resultMap="StudentResult" parameterType="map">
    select 
        stud_id, name,email, phone from Students
    where 
        name=#{name} and email=#{email}
</select>

使用引數替代

<select id="findAllStudentsByNameEmail" resultMap="StudentResult">
    select 
        stud_id, name,email, phone from Students
    where 
        name=#{param1} and email=#{param2}
</select>

註解配置SQL對映器

基於註解的一些內容

  • INSERT
  • UPDATE
  • SELECT
  • DELETE

基本使用

資料插入操作

@Insert("INSERT INTO STUDENTS(NAME,EMAIL,ADDR_ID, PHONE) 
VALUES(#{name},#{email},#{address.addrId},#{phone})")

通過以下註解實現主鍵

@Options(useGeneratedKeys = true, keyProperty = "studId")

通過此註解為任意SQL語句指定主鍵值(使用此註解生成主鍵)

@SelectKey(statement="SELECT STUD_ID_SEQ.NEXTVAL FROM DUAL",
keyProperty="studId", resultType=int.class, before=true)

使用觸發器生成主鍵

@SelectKey(statement="SELECT STUD_ID_SEQ.CURRVAL FROM DUAL",
keyProperty="studId", resultType=int.class, before=false)

結果集對映

@Results(
{
    @Result(id = true, column = "stud_id", property = "studId"),
    @Result(column = "name", property = "name"),
    @Result(column = "email", property = "email"),
    @Result(column = "addr_id", property = "address.addrId")
})

一對一對映

巢狀sql語句形式

@Results(
{
    @Result(id = true, column = "stud_id", property = "studId"),
    @Result(column = "name", property = "name"),
    @Result(column = "email", property = "email"),
    @Result(property = "address", column = "addr_id", one = @One(select = "com.mybatis3.mappers.StudentMapper.findAddressById"))
})

巢狀物件

此種方式並沒有註解形式的實現 ,可以通過在XML中定義對映resultMap集,然後通過@ResultMap進行對映

@ResultMap("com.mybatis3.mappers.StudentMapper.StudentWithAddressResult")

一對多對映

同樣的只有巢狀SQL的形式

 @Result(property = "courses", column = "tutor_id", many = @Many(select = "com.mybatis3.mappers.TutorMapper.findCoursesByTutorId"))