MyBatis学习笔记(二)

MyBatis学习笔记(二)

动态SQL,关联查询,缓存机制,转义字符

个人笔记,如有错误,恳请批评指正。

动态SQL操作

IF语句

修改配置文件deptMapper.xml,添加

<!-- 动态Sql语句 -->
<!-- 根据多个条件生成动态的sql语句,查询信息 -->
<!-- 弊端:当不存在条件时,会查询所有的数据,改用choose可以解决问题 -->
<select id="selectDeptUseIf" parameterType="Dept" resultMap="deptResultMap"><!-- 若字段名与属性名一致可以直接用resultType="Dept" -->
    select * from dept where 1=1
    <!-- 直接写属性,不需要#{},and不能丢 -->
    <if test="deptId!=null">and dept_id = #{deptId}</if>
    <if test="deptAddress!=null">and dept_address = #{deptAddress}</if>
    <if test="deptName!=null">and dept_name = #{deptName}</if>
</select>

修改DeptDaoImpl.java,添加selectListUseIf方法:

//根据参数使用配置文件的IF语句自动填充查询的过滤条件
    public List<Dept> selectDeptUseIf(Dept dept){
        List<Dept> list = null; 
        try {
            session = MybatisSessionFactory.getSession();
            list = session.selectList("cn.ustb.entity.DeptMapper.selectDeptUseIf", dept);
            session.commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
        }
        return list;
    }
WHERE语句

修改配置文件deptMapper.xml,添加

<!-- 动态Where条件 ,一般也需要与if结合使用,与纯if比较,省略了where 1=1-->
<!-- 如果需要去掉1=1,可用where -->
<select id="selectDeptUseWhere" parameterType="Dept" resultMap="deptResultMap">
    select * from dept
    <where>
        <if test="deptId!=null">and dept_id = #{deptId}</if>
        <if test="deptAddress!=null">and dept_address = #{deptAddress}</if>
        <if test="deptName!=null">and dept_name = #{deptName}</if>
    </where>
</select>
choose(when,otherwise)语句

修改配置文件deptMapper.xml,添加

<!-- choose  用choose时,前面的条件符合就不再执行之后的条件-->
<select id="selectDeptUseChoose" parameterType="Dept" resultMap="deptResultMap">
    select * from dept 
    <where>
        <choose>
            <when test="deptId != null">and dept_id = #{deptId}</when>
            <when test="deptAddress != null">and dept_address = #{deptAddress}</when>
            <when test="deptName != null">and dept_name = #{deptName}</when>
            <otherwise>1=2</otherwise>
        </choose>
    </where>
</select>
SET语句

修改配置文件deptMapper.xml,添加

<!-- 动态set语句可以用来更新数据 -->
<update id="updateDeptUseSet" parameterType="Dept">
    update dept 
    <set>
        <if test="deptAddress!=null">dept_address = #{deptAddress}</if>
        <if test="deptName!=null">dept_name = #{deptName}</if>
    </set>
    where dept_id = #{deptId}
</update>
ForEach语句

修改配置文件deptMapper.xml,添加

<!-- 若要查询多个id的数据 -->
<!-- 定义根据多个部门ID查询部门相关部门信息的SQL语句 ,resultMap的值是指集合里元素的类型,parameterType不用指定 -->
<!-- foreach -->
<select id="selectDeptUseForeach" resultMap="deptResultMap">
    select * from dept where dept_id in (
<!-- collection="array或list",array用来对应参数为数组,list对应参数为 集合 -->        
        <foreach collection="array" item="deptId" separator=",">
            #{deptId}
        </foreach>
    )
</select>
include语句

修改配置文件deptMapper.xml,添加

<insert id="insertDeptUseInclude" parameterType="Dept">
    insert into dept
        <include refid="key"></include>
    values
        <include refid="value"></include>
</insert>
<sql id="key">
    <trim suffixOverrides="," prefix="(" suffix=")"> 
        <if test="deptName!=null">dept_name,</if>
        <if test="deptAddress!=null">dept_address,</if>
    </trim>
</sql>
<sql id="value">
    <trim suffixOverrides="," prefix="(" suffix=")">
        <if test="deptName!=null">#{deptName},</if>
        <if test="deptAddress!=null">#{deptAddress},</if><!-- #{} necessary -->
    </trim>
</sql>

关联查询

创建数据库及表:
drop database if exists mybatis;
create database mybatis CHARACTER SET UTF8;
use mybatis;

create table dept(
    dept_id int primary key auto_increment,
    dept_name varchar(50),
    dept_address varchar(50)
);

insert into dept(dept_name,dept_address) values('研发部1部','北京');
insert into dept(dept_name,dept_address) values('研发部2部','广州');
insert into dept(dept_name,dept_address) values('研发部3部','深圳');

create table emp(
    emp_id varchar(20) primary key,
    emp_name varchar(50),
    emp_age int(2),
    emp_gender char(1),
    dept_id int
);

insert into emp(emp_id,emp_name,emp_age,emp_gender,dept_id) values('430726199210102210','张三','18','男','1');
insert into emp(emp_id,emp_name,emp_age,emp_gender,dept_id) values('430726199210102211','李四','20','女','3');
insert into emp(emp_id,emp_name,emp_age,emp_gender,dept_id) values('430726199210102212','王五','19','男','2');

select * from emp;
select * from dept;
select e.*,d.* from emp e inner join dept d on e.dept_id = d.dept_id;
基于association查询(用于多对一或一对一)
创建存在关联的实体类
public class Dept implements Serializable{
    private String deptAddress;
    private String deptName;
    private Integer deptId;

public class Emp implements Serializable{
    private String empId;
    private String empName;
    private String empSex;
    private Dept dept;
配置DeptMapper.xml/EmpMapper.xml

(重点加入级联的查询语句),并映射文件信息到mybatis-config.xml中:
DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ustb.entity.DeptMapper">
    <resultMap type="Dept" id="deptResultMap">
        <id column="dept_id" property="deptId" />
        <result column="dept_name" property="deptName" />
        <result column="dept_address" property="deptAddress" />
    </resultMap>
</mapper>

EmpMapper.xml,配置多对一的关联

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ustb.entity.EmpMapper">
    <resultMap type="Emp" id="empResultMap">
        <id column="emp_id" property="empId"/>
        <result column="emp_name" property="empName"/>
        <result column="emp_age" property="empAge"/>
        <result column="emp_gender" property="empGender"/>
        <association property="dept" column="dept_id" resultMap="cn.ustb.entity.DeptMapper.deptResultMap"></association>
    </resultMap>

    <select id="selectEmp" parameterType="string" resultMap="empResultMap">
        select e.*,d.* from emp e inner join dept d on e.dept_id = d.dept_id
        where e.emp_name = #{empName}
    </select>
</mapper>
配置文件myBatis-config.xml
<!-- 通过别名简化对类的使用 -->
    <typeAliases>
        <typeAlias type="cn.ustb.entity.Dept" alias="Dept"/>
        <typeAlias type="cn.ustb.entity.Emp" alias="Emp"/>
    </typeAliases>
 …….
<!--导入SQL映射文件 -->
    <mappers>
        <mapper resource="cn/ustb/entity/DeptMapper.xml"></mapper>
        <mapper resource="cn/ustb/entity/EmpMapper.xml"></mapper>
    </mappers>
编写EmpDaoImpl.java实现查询
public class EmpDaoImpl {
    private SqlSession session;

    public Emp selectEmp(String empName){
        Emp emp = null;
        try {
            session = MybatisSessionFactory.getSession();
            emp = session.selectOne("cn.ustb.entity.EmpMapper.selectEmp", empName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return emp;
    }
}
基于collection查询(用于一对多或多对多)
编写 Dept.java/Emp.java实体类
Dept.java
public class Dept implements Serializable{
    private String deptAddress;
    private String deptName;
    private Integer deptId;
private List<Emp> emps;

Emp.java
public class Emp implements Serializable{
    private String empId;
    private String empName;
    private String empSex;
配置DeptMapper.xml

DeptMapper.xml文件,配置resultMap(重点是collection配置)和查询SQL语句:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ustb.entity.DeptMapper">
    <resultMap type="Dept" id="deptResultMap">
        <id column="dept_id" property="deptId" />
        <result column="dept_name" property="deptName" />
        <result column="dept_address" property="deptAddress" />
        <collection property="emps" resultMap="cn.ustb.entity.EmpMapper.empResultMap"></collection><!-- 没有column -->
    </resultMap>
    <select id="selectDept" parameterType="String" resultMap="deptResultMap">
        select d.*,e.* from dept d inner join emp e on d.dept_id = e.dept_id
        where d.dept_name = #{deptName}
    </select>
</mapper>
配置EmpMapper.xml文件

不用配置对一关联

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ustb.entity.EmpMapper">
    <resultMap type="Emp" id="empResultMap">
        <id column="emp_id" property="empId"/>
        <result column="emp_name" property="empName"/>
        <result column="emp_age" property="empAge"/>
        <result column="emp_gender" property="empGender"/>
</resultMap>
</mapper>
编写数据库操作类DeptDaoImpl.java
public class DeptDaoImpl {
    private SqlSession session = null;

    public Dept selectDept(String deptName){
        Dept dept = null;
        try {
            session = MybatisSessionFactory.getSession();
            dept = session.selectOne("cn.ustb.entity.DeptMapper.selectDept", deptName);
            session.commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
        }finally{
            MybatisSessionFactory.closeSession();
        }return dept;
    }
}
一对多双向关联查询示例
编写实体类:Dept.java/Emp.java
Dept.java
public class Dept implements Serializable{
    private String deptAddress;
    private String deptName;
    private Integer deptId;
    private List<Emp> emps;

Emp.java
public class Emp implements Serializable{
    private String empId;
    private String empName;
    private String empSex;
    private Dept dept;
编写DeptMapper.xml/EmpMapper.xml文件

DeptMapper.xml
*值得注意的是,如果在各自的resultMap相互配置了引用,在查询时会导致堆栈溢出的异常。解决的办法是在映射文件中分割resultMap,在查询时查询一方的同时避免迭代。*

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ustb.entity.DeptMapper">
    <!-- 缓存的第二级开关,写上即开启 -->
    <!-- 一级默认开启,二级默认关闭,三级默认开启 -->
    <cache eviction="LRU" size="2" readOnly="false"></cache>

    <resultMap type="Dept" id="deptResultMap">
        <id column="dept_id" property="deptId" />
        <result column="dept_name" property="deptName" />
        <result column="dept_address" property="deptAddress" />
    </resultMap>
    <resultMap type="Dept" id="deptExtResultMap" extends="deptResultMap">
        <collection property="emps" resultMap="cn.ustb.entity.EmpMapper.empResultMap"></collection><!-- resultMap是empResultMap而不是empExtResultMap,即没有配置多的属性,避免了相互查询时的内存溢出 -->
    </resultMap>
    <select id="selectDept" parameterType="String" resultMap="deptExtResultMap" useCache="true"><!-- 缓存的三级开关 语句级,默认开启 -->
        select d.*,e.* from dept d inner join emp e on d.dept_id = e.dept_id
        where d.dept_name = #{deptName}
    </select>
    <select id="selectDeptById" parameterType="string" resultMap="deptExtResultMap">
        select d.*,e.* from dept d inner join emp e on d.dept_id = e.dept_id
        where d.dept_id = #{deptId}
    </select>
</mapper>

EmpMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.ustb.entity.EmpMapper">
    <resultMap type="Emp" id="empResultMap">
        <id column="emp_id" property="empId" />
        <result column="emp_name" property="empName" />
        <result column="emp_age" property="empAge" />
        <result column="emp_gender" property="empGender" />
    </resultMap>
    <resultMap type="Emp" id="empExtResultMap" extends="empResultMap">
            <association property="dept" column="dept_id"
            resultMap="cn.ustb.entity.DeptMapper.deptResultMap"></association>
            <!-- 同样,引用的是deprResultMap,没有配置多的属性 -->
    </resultMap>

    <select id="selectEmp" parameterType="string" resultMap="empExtResultMap">
        select
        e.*,d.* from emp e inner join dept d on e.dept_id = d.dept_id
        where
        e.emp_name = #{empName}
    </select>
</mapper>
编写数据操作类:DeptDaoImpl.java/EmpDaoImpl.java

DeptDaoImpl.java,查询部门员工信息,返回类型为List,关键代码:

public List<Dept> selectDeptEmpList(Dept dept){
        SqlSession session=null;
        List<Dept> deps=null;
        try{
        session=MyBatisUtil.getSession();
        deps=session.selectList("cn.ustb.entity.DeptMapper.selectDeptEmpList",dept);
        session.commit();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            session.rollback();
        }finally{
            MyBatisUtil.closeSession();
        }
        return deps;
    }

EmpDaoImpl.java查询员工及其所在部门信息,返回类型为List< Emp >,关键代码

public List<Emp> selectEmpDeptList(Emp emp){
        SqlSession session=null;
        List<Emp> emps=null;
        try{
        session=MyBatisUtil.getSession();
        emps=session.selectList("cn.ustb.entity.EmpMapper.selectEmpDeptList",emp);
        session.commit();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            session.rollback();
        }finally{
            MyBatisUtil.closeSession();
        }
        return emps;
    }

缓存

Mybatis和hibernate一样,也使用缓存;缓存分为一级缓存和二级缓存,一级缓存指在SqlSession内共享数据;二级缓存能被所有的SqlSession共享。

全局缓存配置(一级缓存)

在mybatis-config.xml的主配置文件中进行配置:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 默认有启用全局缓存的,禁用可以把value设为false,如果这里设为false,Mapper.xml或SQL语句级的缓存配置不再起作用 -->
        <setting name="cacheEnabled" value="true"/>     
    </settings>
<!—省略其它配置信息 -->
</configuration>
Mapper文件级缓存配置(二级缓存)

使用二级缓存机制:需要开启全局缓存,文件级缓存 ,语句级缓存,才能使用二级缓存。默认情况下文件级缓存没有开启

<!-- 缓存的第二级开关,写上即开启 -->
    <!-- 一级默认开启,二级默认关闭,三级默认开启 -->
    <cache eviction="LRU" size="2" readOnly="false"></cache>

关于二级缓存的配置,在使用者手册中有详细说明,摘取如下内容:

可用的回收算法如下:
• LRU – 最近最少使用:移出最近最长时间内都没有被使用的对象。
• FIFO – 先进先出:移除最先进入缓存的对象。
• SOFT – 软引用: 基于垃圾回收机制和软引用规则来移除对象(空间内存不足时才进行回收)。
• WEAK – 弱引用: 基于垃圾回收机制和弱引用规则(垃圾回收器扫描到时即进行回收)。
默认使用LRU。

flushInterval :设置任何正整数,代表一个以毫秒为单位的合理时间。默认是没有设置,因此 没有刷新间隔时间被使用,在语句每次调用时才进行刷新。
Size:属性可以设置为一个正整数,您需要留意您要缓存对象的大小和环境中可用的内存空间。 默认是1024。
readOnly:属性可以被设置为true 或false。只读缓存将对所有调用者返回同一个实例。因此这些对象都不能被修改,这可以极大的提高性能。可写的缓存将通过序列化来返回一个缓存对象的拷贝。这会比较慢,但是比较安全。所以默认值是false。

缓存配置分析:
<!-- 
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="false"/>
创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。可用的收回策略有以下几种, 默认的是 LRU:
1. LRU – 最近最少使用的:移除最长时间不被使用的对象。 
2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 
3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。 
4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval:刷新间隔时间,可以被设置为任意的正整数,单位毫秒。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size:内存资源数目,可以被设置为任意正整数。默认值是1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。
 -->
<cache eviction="LRU" size="2" readOnly="false" />
SQL语句级缓存配置

在相关的Mapper.xml文件中配置SQL查询,关键代码如下(示例):

<!--  useCache默认值为true,设为false时缓存不起作用 -->
    <select id="selectOne" parameterType="int" resultMap="deptResultMap" useCache="true" >
        select * from dept where dept_id=#{id}
    </select>

XML 中的特殊字符处理

如果 MyBatis 使用 XML 配置,那不可避免地会遇到一些对 XML 来说是特殊的字符。如小于号 “<”,因此要进行转义。主要有两个方式:

使用转义实体

下面是五个在 XML 文档中预定义好的转义实体:
- &lt; < 小于号
- &gt; > 大于号
- &amp; &
- &apos; ’ 单引号
- &quot; ” 双引号
- 小于等于“<=”,其转义为:&lt;=
- 大小等于“>=”,转义为:&gt;=

使用 CDATA 部件

CDATA 部件以”

<select id= "selectBlog_use_collection" resultMap= "blogResult" >
<![CDATA[ SELECT id , title, author_id as authored FROM BLOG WHERE ID > 0 and ID < 10 ]]> </select>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值