主要內(nèi)容
1. 應(yīng)用<select>元素實現(xiàn)數(shù)據(jù)查詢
2. <insert><update><delete>元素更新數(shù)據(jù)
3. 應(yīng)用<sql>元素實現(xiàn)重用,應(yīng)用緩存設(shè)置
4. 查詢返回結(jié)果的封裝處理
5. 動態(tài)SQL應(yīng)用
1. 應(yīng)用<select>元素實現(xiàn)數(shù)據(jù)查詢
select元素用來從數(shù)據(jù)庫中查詢數(shù)據(jù)結(jié)果,一個最簡單的select實現(xiàn)方式如下所示:

1.1 <select>元素屬性說明
select元素屬性規(guī)范查詢中的動作。諸如,如何傳遞查詢參數(shù),映射返回結(jié)果,是否使用緩存,查詢超時限定等特性。
<select>常用的屬性

1.2 使用parameterType設(shè)置參數(shù)
- parameterType是int, resultType是某個類的例子
<select id="findStuByAge" resultType="stu" parameterType="int">
<![CDATA[select * from student where age > #{age}]]>
</select>
代碼實現(xiàn)
public List<Student> findStuByAge(int age){
return SqlSessionFactoryManager.getSqlSession().selectList("students.findStuByAge",age);
}
- parameterType是string, resultType是map的例子
<select id="findStuByEmail" resultType="map" parameterType="string">
<![CDATA[select * from student where email = #{email}]]>
</select>
代碼實現(xiàn)
public Map<String, Object> findStuByEmail(){
String email = "123@163.com";
return SqlSessionFactoryManager.getSqlSession().selectOne("students.findStuByEmail",email);
}
- parameterType是map, resultType是某個類的例子
<select id="findStuByArgs" resultType="stu" parameterType="map">
<![CDATA[select * from student where email <> #{email} and age > #{age}
and birth > #{birth}
]]>
</select>
代碼實現(xiàn)
public List<Student> findStuByArgs(){
String email = "123@163.com";
int age = 18;
String birth = "1900-01-01";
Map<String, Object> map = new HashMap<>();
map.put("email",email);
map.put("age",age);
map.put("birth",birth);
return SqlSessionFactoryManager.getSqlSession()
.selectList("students.findStuByArgs",map);
}
2<insert><update><delete>元素更新數(shù)據(jù)
2.1 <insert><update>通用屬性
除了具有<select>等元素的通用屬性外,<insert>和<update>還具有以下相同常用屬性:

keyProperty和keyColumn相互對應(yīng)。
2.2 使用<insert>元素映射insert語句
保存一個department表的信息到數(shù)據(jù)庫中
mapper.xml中的內(nèi)容:
<insert id="saveDepartment" parameterType="map" keyColumn="ID"
keyProperty="id" statementType="PREPARED">
<![CDATA[insert into department(id, name, code, newdate, descs)
values(#{id},#{name},#{code},#{newdate},#{descs})]]>
</insert>
代碼實現(xiàn):
public int saveDepartment(Map<String, Object> map){
System.out.println("執(zhí)行保存");
//獲取sqlSession實例
SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
int res = sqlSession.insert("deps.saveDepartment",map);
sqlSession.commit();
sqlSession.close();
return res;
}
2.3 使用<update>元素映射update語句
根據(jù)指定id更新數(shù)據(jù)庫的表
mapper.xml中的內(nèi)容:
<update id="updateDepartmentById" parameterType="map" flushCache="true" statementType="PREPARED">
<![CDATA[
update department
set descs = #{descs}, name = #{name}
where id = #{id}]]>
</update>
代碼實現(xiàn):
/**
* 實現(xiàn)按照部門id更新部門信息
* @param map 部門map
* @return
*/
public int updateDepartmentById(Map<String, Object> map){
System.out.println("執(zhí)行修改");
//獲取sqlSession實例
SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
int res = sqlSession.update("deps.updateDepartmentById",map);
sqlSession.commit();
sqlSession.close();
return res;
}
2.4 使用<delete>元素映射delete語句
根據(jù)給定的id刪除department的內(nèi)容
mapper.xml中的內(nèi)容:
<delete id="removeDepById" parameterType="string" flushCache="true" statementType="PREPARED">
<![CDATA[
delete from department
where id = #{id}]]>
</delete>
代碼實現(xiàn):
/**
* 按照指定的部門id刪除此部門
* @param depid 部門id
* @return int
*/
public int removeDepById(String depid){
System.out.println("執(zhí)行刪除");
//獲取sqlSession實例
SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
int res = sqlSession.delete("deps.removeDepById", depid);
sqlSession.commit();
sqlSession.close();
return res;
}
3.應(yīng)用<sql>元素實現(xiàn)重用,應(yīng)用緩存設(shè)置
3.1 <sql>元素實現(xiàn)重用
//定義一個重復(fù)使用的sql語句塊
<!--可重用的sql塊,可以被當(dāng)前映射中任何select, update及insert delete應(yīng)用-->
<sql id="DEPCommons">
id, name, code, newdate, descs </sql>
//其他語句中調(diào)用
<!--使用include引用sql元素不能使用常量語義符號包圍, 否則無法進行解析-->
<select id="queryDepList" resultType="dep" fetchSize="3">
select <include refid = "DEPCommons"/> from department limit 0,3;
<!--<![CDATA[select * from department limit 0,3;]]>-->
</select>
3.2 應(yīng)用緩存設(shè)置
數(shù)據(jù)緩存可以增加數(shù)據(jù)的訪問操作效率,myBatis提供了設(shè)置sql的緩存策略和在sql映射中引用緩存策略。
myBatis使用cache元素在sql映射中設(shè)置緩存策略及使用ref-cache引用緩存策略。
3.2.1 myBatis緩存機制

myBatis一級緩存
一級緩存中每個SqlSession獨享緩存數(shù)據(jù)
導(dǎo)致一級緩存查詢失敗的因素

myBatis二級緩存
二級緩存中每個mapper中SqlSession會共享緩存數(shù)據(jù)
設(shè)置sql緩存

mybatis提供的幾種緩存策略類型:

應(yīng)用緩存
cache-ref元素實現(xiàn)從一個mapper中引用當(dāng)前的mapper中的緩存策略并應(yīng)用。

導(dǎo)致二級緩存查詢失敗的原因

二級緩存的缺陷

緩存策略
使用第三方專業(yè)緩存工具代替myBatis二級緩存[Ehcache, Redis]
4. 查詢返回結(jié)果的封裝處理
myBatis通常在映射<select>元素執(zhí)行sql使用returnType設(shè)置返回結(jié)果類型,有時需要對查詢返回結(jié)果進行特殊處理;<select>元素提供了returnMap屬性為查詢返回結(jié)果進行處理的更靈活方式。
returnMap屬性是對sql映射中某個returnMap元素的引用,而returnMap元素的定義決定了如何處理查詢返回結(jié)果。
4.1 resultMap基本映射應(yīng)用
Q: 數(shù)據(jù)庫表student列名稱和Student.Java類型屬性名稱不匹配,導(dǎo)致無法直接使用returnType指定為Student Java類型
S: 使用resultMap元素自定義返回結(jié)果的處理并映射記錄行為Student Java類型,使用resultMap屬性設(shè)置引用resultMap元素。
E:
<!--使用列標(biāo)簽與實體bean屬性保持一致達到自動映射的目的-->
<select id="queryProductList" resultType="pro" useCache="true" statementType="PREPARED">
<![CDATA[
select id proId,code proCode,name proName,price proPrice,quality proQuantity,descs proDescs from product;
]]>
</select>
<resultMap id="ProMapping" type="pro" autoMapping="false">
<id column="ID" property="proId" javaType="string" jdbcType="VARCHAR"/>
<result column="CODE" property="proCode" javaType="string" jdbcType="VARCHAR"/>
<result column="NAME" property="proName" javaType="string" jdbcType="VARCHAR"/>
<result column="PRICE" property="proPrice" javaType="double" jdbcType="DOUBLE"/>
<result column="QUALITY" property="proQuantity" javaType="integer" jdbcType="INTEGER"/>
<result column="DESCS" property="proDescs" javaType="string" jdbcType="VARCHAR"/>
</resultMap>
resultMap和resultType封裝過程中只會有一個存在
4.2 resultMap元素說明
4.2.1 resultMap屬性

4.2.2 resultMap子元素

- 高級復(fù)雜結(jié)果關(guān)聯(lián)映射(一對多):collection的使用
使用resultMap元素映射復(fù)雜的一對多關(guān)聯(lián)
<select id="structTreeMap" resultMap="dep_emp_sal_map" statementType="PREPARED">
<![CDATA[
select d.id did, d.name dname, e.id eid, e.name ename,
s.id sid, s.should, s.actual, s.mapYearMon
from department d inner join emp e on d.id = e.DEPID
inner join salary s on e.id = s.empId;
]]>
</select>
<!--使用resultMap元素映射復(fù)雜的一對多關(guān)聯(lián)-->
<resultMap id="dep_emp_sal_map" type="dep" autoMapping="false">
<id column="did" property="id" javaType="string" jdbcType="VARCHAR"/>
<result column="dname" property="name" javaType="string" jdbcType="VARCHAR"/>
<collection property="employeeList" autoMapping="false" ofType="emp">
<id column="eid" property="id" javaType="string" jdbcType="VARCHAR"/>
<result column="ename" property="name" javaType="string" jdbcType="VARCHAR"/>
<collection property="salaryList" ofType="sal" autoMapping="false">
<id column="sid" property="id" javaType="string" jdbcType="VARCHAR"/>
<result column="should" property="should" javaType="integer" jdbcType="INTEGER"/>
<result column="actual" property="actual" javaType="integer" jdbcType="INTEGER"/>
<result column="mapYearMon" property="mapYearMon" javaType="date" jdbcType="DATE"/>
</collection>
</collection>
</resultMap>
使用resultMap實現(xiàn)關(guān)聯(lián)映射,實體數(shù)據(jù)使用map進行封裝,避免定義更多的VO類
<!--將一對多關(guān)聯(lián)數(shù)據(jù)實體映射為map-->
<select id="structTreeMap2" resultMap="depAndempAndsalAndmap" statementType="PREPARED">
<![CDATA[
select d.id did, d.name dname, e.id eid, e.name ename,
s.id sid, s.should, s.actual, s.mapYearMon
from department d inner join emp e on d.id = e.DEPID
inner join salary s on e.id = s.empId;
]]>
</select>
<!--使用resultMap元素映射復(fù)雜的一對多關(guān)聯(lián),實體數(shù)據(jù)使用Map進行封裝,減少使用實體類-->
<resultMap id="depAndempAndsalAndmap" type="treeMap" autoMapping="false">
<id column="did" property="id" javaType="string" jdbcType="VARCHAR"/>
<result column="dname" property="name" javaType="string" jdbcType="VARCHAR"/>
<collection property="employeeList" autoMapping="false" ofType="treeMap">
<id column="eid" property="id" javaType="string" jdbcType="VARCHAR"/>
<result column="ename" property="name" javaType="string" jdbcType="VARCHAR"/>
<collection property="salaryList" ofType="treeMap" autoMapping="false">
<id column="sid" property="id" javaType="string" jdbcType="VARCHAR"/>
<result column="should" property="should" javaType="integer" jdbcType="INTEGER"/>
<result column="actual" property="actual" javaType="integer" jdbcType="INTEGER"/>
<result column="mapYearMon" property="mapYearMon" javaType="date" jdbcType="DATE"/>
</collection>
</collection>
</resultMap>
提示: id元素是嵌套映射中非常重要的角色,通常必須要映射它,如果不使用id作為標(biāo)識結(jié)果,性能會有很大損耗。
- 高級復(fù)雜結(jié)果關(guān)聯(lián)映射(一對一): myBatis提供resultMap元素的association子元素實現(xiàn)一對一關(guān)聯(lián)映射
- 使用association元素的select屬性指向一條sql查詢語句描述如何封裝結(jié)果
- 使用association元素的resultMap屬性指向association元素描述如何封裝結(jié)果(效率高)
使用association元素的select屬性指向一條sql查詢語句描述如何封裝結(jié)果
<!-- 查詢員工 -->
<select id="findEmpAndDoc" resultMap="findEmpMap" statementType="PREPARED">
select * from emp
</select>
<resultMap id="findEmpMap" type="emp" autoMapping="false">
<id column="id" javaType="string" jdbcType="VARCHAR" property="id"/>
<result column="name" javaType="string" jdbcType="VARCHAR" property="name"/>
<!--column指定應(yīng)該如何進行映射-->
<association property="doc" autoMapping="false" column="id" javaType="doc"
select="findDocMap"/>
</resultMap>
<!--查詢檔案-->
<select id="findDocMap" resultType="doc" parameterType="string" statementType="PREPARED">
select * from document where empid = #{empid};
</select>
使用association元素的resultMap屬性指向association元素描述如何封裝結(jié)果(效率高, 僅僅去數(shù)據(jù)庫之中查詢一次)
<!-- 查詢員工對象和對應(yīng)的檔案對象集合 -->
<select id="findEmployeeAndDocument" resultMap="findEmpMap2" statementType="PREPARED">
select e.id eid,e.name, d.id did, d.number from emp e inner join document d on
e.id = d.empid;
</select>
<!--映射員工查詢返回結(jié)果-->
<resultMap id="findEmpMap2" type="emp" autoMapping="false">
<id column="eid" javaType="string" jdbcType="VARCHAR" property="id"/>
<result column="name" javaType="string" jdbcType="VARCHAR" property="name"/>
<association property="doc" javaType="doc" autoMapping="false"
resultMap="docMap" column="empid"/>
</resultMap>
<!--映射用戶檔案查詢返回結(jié)果-->
<resultMap id="docMap" type="doc" autoMapping="false">
<id column="did" javaType="string" jdbcType="VARCHAR" property="id"/>
<result column="number" javaType="string" jdbcType="VARCHAR" property="number"/>
</resultMap>
5. 動態(tài)SQL應(yīng)用

5.1 if
if元素是構(gòu)成動態(tài)SQL語句非常重要的和使用比較頻繁的元素,它表示執(zhí)行一個邏輯判斷,如果為true則執(zhí)行if元素之內(nèi)的內(nèi)容,if元素有唯一的一個test屬性用來接收一個布爾表達式,if經(jīng)常用來組織where語句的連接生成
<!--動態(tài)sql if的使用-->
<select id="queryEmpListByGender" parameterType="int" resultType="emp" statementType="PREPARED">
select id,name,birth,phone from emp
<if test="'gender' != null">
where gender = #{gender}
</if>
</select>
<!--動態(tài)sql if的使用2-->
<select id="queryEmpListByMap" parameterType="map" resultType="emp" statementType="PREPARED">
select id,name,birth,phone from emp
<if test="gender != null">
where gender = #{gender}
</if>
<if test="name != null">
and name like concat(#{name},"%")
/*and name like '${name}%'*/
</if>
</select>
5.2 choose, when, otherwise
choose when otherwise類似于Java中的switch分支語句
<!--choose when otherwise 動態(tài)sql-->
<select id="queryEmpListByMap2" parameterType="map" resultType="emp" statementType="PREPARED">
select id,name,birth,phone from emp where 1 = 1
<choose>
<when test="gender != null">and gender = #{gender}</when>
<when test="name != null">and name not like '${name}%'</when>
<when test="start != null and ends != null">
and birth between #{start} and #{ends}
</when>
<otherwise>
<if test="id != null">
and id = #{id}
</if>
</otherwise>
</choose>
</select>
5.3 trim, where, set
5.3.1 where
where元素用來代替用戶手寫的where sql關(guān)鍵字,它基本可以解決沒有給定條件時而出現(xiàn)錯誤sql語法
where元素能夠知道如果它包含的標(biāo)簽中有返回值的話,它就插入一個where, 如果標(biāo)簽返回的內(nèi)容以AND或OR開頭的,則它會剔除掉
示例:
<!--動態(tài)sql 使用where元素代替手寫where 避免手寫where出錯-->
<select id="queryEmpListByMap3" parameterType="map" resultType="emp" statementType="PREPARED">
select id,name,birth,phone from emp
<where>
<choose>
<when test="gender != null">and gender = #{gender}</when>
<when test="name != null">and name not like '${name}%'</when>
<when test="start != null and ends != null">
and birth between #{start} and #{ends}
</when>
<otherwise>
<if test="id != null">
and id = #{id}
</if>
</otherwise>
</choose>
</where>
</select>
5.3.2 trim
trim元素可以用來代替where set等元素設(shè)置自定義動態(tài)sql語句,它有三個屬性:
prefix: 指定前綴
suffix: 指定后綴
prefixOverrides: 設(shè)置分隔符(空格也屬于分隔符之列)
示例:
<!--動態(tài)sql trim 元素替代 where-->
<select id="queryEmpListByMap4" parameterType="map" resultType="emp" statementType="PREPARED">
select id,name,birth,phone from emp
<trim prefix="where" prefixOverrides="and|or">
<if test="gender != null">gender = #{gender}</if>
<if test="name != null">and name like concat(#{name},'%')</if>
</trim>
</select>
5.3.3 set
set元素用來實現(xiàn)update語句的更新,它取代set關(guān)鍵字設(shè)置更新列信息。
示例:
<!--使用set元素代替手寫set更新sql語句關(guān)鍵字-->
<update id="modifyEmployee" parameterType="emp" statementType="PREPARED">
update emp
<set>
<if test="name != null">name = #{name},</if>
<if test="gender != null">gender = #{gender},</if>
<if test="address != null">address = #{address}</if>
</set>
where id = #{id}
</update>
5.4 foreach
foreach是一個迭代功能的動態(tài)sql元素,通常在條件包含in或not in時使用其填充條件。
MyBatis會自動將有序集合及數(shù)組包裝成一個Map處理,并使用它的名稱作為key。List實例將使用"list"作為鍵,數(shù)組實例以"array"作為鍵。
示例:
<!--使用foreach迭代參數(shù)集合-->
<select id="queryEmpListForAddress" resultType="emp" statementType="PREPARED">
select * from emp where address in
<foreach collection="list" item="ele" index="index" separator=","
open="(" close=")">
#{ele}
</foreach>
</select>
<!--使用foreach迭代參數(shù)集合(多參數(shù))-->
<select id="queryEmpListForAddress2" resultType="emp" parameterType="map" statementType="PREPARED">
select * from emp where
birth between #{startTime} and #{endTime} and address in
<foreach collection="addList" index="index" item="ele" separator=","
open="(" close=")">
#{ele}
</foreach>
</select>