首页 > 学院 > 开发设计 > 正文

MyBatis学习笔记(二)

2019-11-08 02:58:10
字体:
来源:转载
供稿:网友

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.javapublic class Dept implements Serializable{ private String deptAddress; private String deptName; private Integer deptId;private List<Emp> emps;Emp.javapublic 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.javapublic class Dept implements Serializable{ private String deptAddress; private String deptName; private Integer deptId; private List<Emp> emps;Emp.javapublic 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>


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表