主要内容
1. 应用<select>元素实现数据查询
2. <insert><update><delete>元素更新数据
3. 应用<sql>元素实现重用,应用缓存设置
4. 查询返回结果的封装处理
5. 动态SQL应用
1. 应用<select>元素实现数据查询
select元素用来从数据库中查询数据结果,一个最简单的select实现方式如下所示:
1.1 <select>元素属性说明
select元素属性规范查询中的动作。诸如,如何传递查询参数,映射返回结果,是否使用缓存,查询超时限定等特性。
<select>常用的属性
1.2 使用parameterType设置参数
- parameterType是int, resultType是某个类的例子
<select id="findStuByAge" resultType="stu" parameterType="int">
<![CDATA[select * from student where age > #{age}]]>
</select>
代码实现
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>
代码实现
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>
代码实现
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>元素更新数据
2.1 <insert><update>通用属性
除了具有<select>等元素的通用属性外,<insert>和<update>还具有以下相同常用属性:
keyProperty和keyColumn相互对应。
2.2 使用<insert>元素映射insert语句
保存一个department表的信息到数据库中
mapper.xml中的内容:
<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>
代码实现:
public int saveDepartment(Map<String, Object> map){
System.out.println("执行保存");
//获取sqlSession实例
SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
int res = sqlSession.insert("deps.saveDepartment",map);
sqlSession.commit();
sqlSession.close();
return res;
}
2.3 使用<update>元素映射update语句
根据指定id更新数据库的表
mapper.xml中的内容:
<update id="updateDepartmentById" parameterType="map" flushCache="true" statementType="PREPARED">
<![CDATA[
update department
set descs = #{descs}, name = #{name}
where id = #{id}]]>
</update>
代码实现:
/**
* 实现按照部门id更新部门信息
* @param map 部门map
* @return
*/
public int updateDepartmentById(Map<String, Object> map){
System.out.println("执行修改");
//获取sqlSession实例
SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
int res = sqlSession.update("deps.updateDepartmentById",map);
sqlSession.commit();
sqlSession.close();
return res;
}
2.4 使用<delete>元素映射delete语句
根据给定的id删除department的内容
mapper.xml中的内容:
<delete id="removeDepById" parameterType="string" flushCache="true" statementType="PREPARED">
<![CDATA[
delete from department
where id = #{id}]]>
</delete>
代码实现:
/**
* 按照指定的部门id删除此部门
* @param depid 部门id
* @return int
*/
public int removeDepById(String depid){
System.out.println("执行删除");
//获取sqlSession实例
SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
int res = sqlSession.delete("deps.removeDepById", depid);
sqlSession.commit();
sqlSession.close();
return res;
}
3.应用<sql>元素实现重用,应用缓存设置
3.1 <sql>元素实现重用
//定义一个重复使用的sql语句块
<!--可重用的sql块,可以被当前映射中任何select, update及insert delete应用-->
<sql id="DEPCommons">
id, name, code, newdate, descs </sql>
//其他语句中调用
<!--使用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 应用缓存设置
数据缓存可以增加数据的访问操作效率,myBatis提供了设置sql的缓存策略和在sql映射中引用缓存策略。
myBatis使用cache元素在sql映射中设置缓存策略及使用ref-cache引用缓存策略。
3.2.1 myBatis缓存机制
myBatis一级缓存
一级缓存中每个SqlSession独享缓存数据
导致一级缓存查询失败的因素
myBatis二级缓存
二级缓存中每个mapper中SqlSession会共享缓存数据
设置sql缓存
mybatis提供的几种缓存策略类型:
应用缓存
cache-ref元素实现从一个mapper中引用当前的mapper中的缓存策略并应用。
导致二级缓存查询失败的原因
二级缓存的缺陷
缓存策略
使用第三方专业缓存工具代替myBatis二级缓存[Ehcache, Redis]
4. 查询返回结果的封装处理
myBatis通常在映射<select>元素执行sql使用returnType设置返回结果类型,有时需要对查询返回结果进行特殊处理;<select>元素提供了returnMap属性为查询返回结果进行处理的更灵活方式。
returnMap属性是对sql映射中某个returnMap元素的引用,而returnMap元素的定义决定了如何处理查询返回结果。
4.1 resultMap基本映射应用
Q: 数据库表student列名称和Student.Java类型属性名称不匹配,导致无法直接使用returnType指定为Student Java类型
S: 使用resultMap元素自定义返回结果的处理并映射记录行为Student Java类型,使用resultMap属性设置引用resultMap元素。
E:
<!--使用列标签与实体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子元素
- 高级复杂结果关联映射(一对多):collection的使用
使用resultMap元素映射复杂的一对多关联
<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元素映射复杂的一对多关联-->
<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实现关联映射,实体数据使用map进行封装,避免定义更多的VO类
<!--将一对多关联数据实体映射为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元素映射复杂的一对多关联,实体数据使用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作为标识结果,性能会有很大损耗。
- 高级复杂结果关联映射(一对一): myBatis提供resultMap元素的association子元素实现一对一关联映射
- 使用association元素的select属性指向一条sql查询语句描述如何封装结果
- 使用association元素的resultMap属性指向association元素描述如何封装结果(效率高)
使用association元素的select属性指向一条sql查询语句描述如何封装结果
<!-- 查询员工 -->
<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指定应该如何进行映射-->
<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元素描述如何封装结果(效率高, 仅仅去数据库之中查询一次)
<!-- 查询员工对象和对应的档案对象集合 -->
<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>
<!--映射员工查询返回结果-->
<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>
<!--映射用户档案查询返回结果-->
<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. 动态SQL应用
5.1 if
if元素是构成动态SQL语句非常重要的和使用比较频繁的元素,它表示执行一个逻辑判断,如果为true则执行if元素之内的内容,if元素有唯一的一个test属性用来接收一个布尔表达式,if经常用来组织where语句的连接生成
<!--动态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>
<!--动态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 动态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关键字,它基本可以解决没有给定条件时而出现错误sql语法
where元素能够知道如果它包含的标签中有返回值的话,它就插入一个where, 如果标签返回的内容以AND或OR开头的,则它会剔除掉
示例:
<!--动态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等元素设置自定义动态sql语句,它有三个属性:
prefix: 指定前缀
suffix: 指定后缀
prefixOverrides: 设置分隔符(空格也属于分隔符之列)
示例:
<!--动态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元素用来实现update语句的更新,它取代set关键字设置更新列信息。
示例:
<!--使用set元素代替手写set更新sql语句关键字-->
<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是一个迭代功能的动态sql元素,通常在条件包含in或not in时使用其填充条件。
MyBatis会自动将有序集合及数组包装成一个Map处理,并使用它的名称作为key。List实例将使用"list"作为键,数组实例以"array"作为键。
示例:
<!--使用foreach迭代参数集合-->
<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迭代参数集合(多参数)-->
<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>