通過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標籤
及if
、choose
等標籤可對欄位進行判斷,看是否需要新增到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>
當if
中test
條件成立時, 才會新增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>
假如說name
和gender
的值都不為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"))