MyBatis --- 动态SQL、缓存机制
有的时候需要根据要查询的参数动态的拼接SQL语句
常用标签:
- if:字符判断
- choose【when...otherwise】:分支选择
- trim【where,set】:字符串截取,其中where标签封装查询条件,set标签封装修改条件
- foreach:
if案例
1)在EmployeeMapper接口文件添加一个方法
public Student getStudent(Student student);
2)如果要写下列的SQL语句,只要是不为空,就作为查询条件,如下所示,这样写实际上是有问题的,所以我们要写成动态SQL语句:
<select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee">
select *from tbl_employee where id = #{id} and user_name = #{userName} and email = #{email} and gender = #{gender}
</select>
3)用if标签改写为动态SQL,如下所示:
<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
SELECT *
FROM student
where
<if test="id != null">
id=#{id}
</if>
<if test="name !=null and name!=''">
and name=#{name}
</if>
<if test="password !=null and password !=''">
and password=#{password}
</if>
<if test="email !=null and email !=''">
and email=#{email}
</if>
</select>
4)测试代码
@Test
public void TestgetStudent(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
Student student = new Student(4,"jack", "111", "jack@qq.com");
System.out.println(student);
Student student2 = bean.getStudent(student);
System.out.println(student2);
}
#测试结果没问题,
但是仔细来说,上面的sql语句是有问题的,当我们不给动态sql语句传递id值的时候,sql语句的拼装就会有问题!【name前有一个and】
- where 标签
<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
SELECT *
FROM student
<where>
<if test="id != null">
id=#{id}
</if>
<if test="name !=null and name!=''">
and name=#{name}
</if>
<if test="password !=null and password !=''">
and password=#{password}
</if>
<if test="email !=null and email !=''">
and email=#{email}
</if>
</where>
</select>
3.需要注意:where标签只会去掉第一个多出来的and或者or
也就是说使用where标签有时候还是不能解决问题的,那怎么办呢?我们这里可以使用trim标签!
- trim标签:可以自定义字符串的截取规则
<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
SELECT *
FROM student
<trim prefix="where" prefixOverrides="and">
<if test="id != null">
id=#{id}
</if>
<if test="name !=null and name!=''">
and name=#{name}
</if>
<if test="password !=null and password !=''">
and password=#{password}
</if>
<if test="email !=null and email !=''">
and email=#{email}
</if>
</trim>
</select>
- choose标签:分支选择,类似于Java中的带了break的switch...case
相当于确保了第一个case 符合之后,就跳出
案例演示:
1.在EmployeeMapper接口中添加一个方法
public List<Student> getStus(Student student);
2.sql映射文件
<select id="getStus" resultType="com.neuedu.mybatis.entity.Student">
select * from student
<where>
<choose>
<when test="id !=null">
id = #{id}
</when>
<when test="name !=null and name!=''">
name = #{name}
</when>
<when test="password !=null and password!=''">
password = #{password}
</when>
<when test="email !=null and email!=''">
email = #{email}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</where>
</select>
- set标签:字符串截取,可以写在trim里面
set元素会动态前置set关键字,同时也会消除无关的逗号
1)在EmployeeMapper中添加一个更新的方法
public void updateStu(Student student);
2)在sql映射文件中,填写相应的sql语句,如下所示【set标签可以将字段后面的逗号去掉】
<update id="updateStu">
update student
<set>
<if test="name !=null and name!=''">
name=#{name},
</if>
<if test="password !=null and password !=''">
password=#{password},
</if>
<if test="email !=null and email !=''">
email=#{email}
</if>
</set>
where id = #{id}
</update>
3)测试类代码为
@Test
public void TestUpdateStu(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
bean.updateStu(new Student(4, "jackk", null, null));
}
将set标签用trim标签代替
<update id="updateStu">
update student
<trim prefix="set" suffixOverrides=",">
<if test="name !=null and name!=''">
name=#{name},
</if>
<if test="password !=null and password !=''">
password=#{password},
</if>
<if test="email !=null and email !=''">
email=#{email}
</if>
</trim>
where id = #{id}
</update>
- foreach:遍历元素
public List<Student> getStuByIdForEach(@Param("ids")List<Integer> ids);
2.在MyBatis的sql映射文件中写相应的代码
<select id="getStuByIdForEach" resultType="com.neuedu.mybatis.entity.Student">
select * from student
where id
in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
3.测试类代码
@Test
public void getStuByIdForEach(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
List<Integer> list = Arrays.asList(16,17,18,19);
List<Student> stuByIdForEachlist = bean.getStuByIdForEach(list);
for (Student student : stuByIdForEachlist) {
System.out.println(student);
}
}
foreach标签还可以用于批量保存数据,
1.在EmployeeMapper接口类中添加批量插入的方法
public void insertStus(@Param("stus")List<Student> student);
2.在EmployeeMapper.xml的sql映射文件中添加响应的语句
foreach 中用 collection,collection中是从Mapper接口传来的参数,separator是去掉中间符号
<insert id="insertStus">
insert into student (name,password,email) values
<foreach collection="stus" item="stu" separator=",">
(#{stu.name},#{stu.password},#{stu.email})
</foreach>
</insert>
3.测试代码
@Test
public void TestInsertStus(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
List<Student> list = new ArrayList<Student>();
list.add(new Student("123","123", "123"));
list.add(new Student("123","123", "123"));
list.add(new Student("123","123", "123"));
bean.insertStus(list);
}
MyBatis-缓存机制
一级缓存:
案例:测试一级缓存【默认是开启的】
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class); Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp); Employee emp2 = mapper.getEmpInfoById(4);
System.out.println(emp2); System.out.println(emp == emp2); session.commit();
session.close();
}
一级缓存失效的情况【4种】(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询)
1.sqlSession不同,重新定义SqlSession
将返回两条select语句
将返回false,说明emp2不是emp的缓存
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp); SqlSession session2 = sqlSessionFactory.openSession();
EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);
Employee emp2 = mapper2.getEmpInfoById(4);
System.out.println(emp2); System.out.println(emp == emp2); session.commit();
session.close();
}
2.SqlSession相同,但是查询条件不一样[当前缓存中还没有这个数据]
就是相当于根据不同条件再次查找
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class); Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp); Employee emp2 = mapper.getEmpInfoById(16);
System.out.println(emp2); System.out.println(emp == emp2); session.commit();
session.close();
}
3.SqlSession相同,但是两次查询之间执行了增删改操作【这次增删改可能对当前数据有影响】
因为默认自动刷新了缓存
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class); Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp); mapper.deleteEmp(16); Employee emp2 = mapper.getEmpInfoById(4);
System.out.println(emp2); System.out.println(emp == emp2); session.commit();
session.close();
}
4.SqlSession相同,手动清除了一级缓存[缓存清空]
手动清除了缓存,所以得重新查找
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class); Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp); session.clearCache(); Employee emp2 = mapper.getEmpInfoById(4);
System.out.println(emp2); System.out.println(emp == emp2); session.commit();
session.close();
}
二级缓存:
案例:
1)开启全局二级缓存配置:
<setting name="cacheEnabled" value="true"/>
2)去mapper.xml中配置使用二级缓存
<cache eviction="FIFO" size="100" readOnly="false"/>
3)我们的POJO需要实现序列化接口[implements Serializable]
4)必须先关闭之前的sqlsession对象
测试:
可以看到只发送了一次SQL语句,第二次查询时从二级缓存中拿到的数据,并没有发送新的sql语句。
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp);
session.close(); SqlSession session2 = sqlSessionFactory.openSession();
EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);
Employee emp2 = mapper2.getEmpInfoById(4);
System.out.println(emp2);
session2.close();
}
需要注意的是:只有一级缓存中关闭的情况下,二级缓存才会被使用。
需要注意的是:在哪个Mapper.xml文件中开启了<cache>缓存标签,哪个Mapper中就开启了二级缓存。
MyBatis --- 动态SQL、缓存机制的更多相关文章
- mybatis原理分析学习记录,mybatis动态sql学习记录
以下个人学习笔记,仅供参考,欢迎指正. MyBatis 是支持定制化 SQL.存储过程以及高级映射的持久层框架,其主要就完成2件事情: 封装JDBC操作 利用反射打通Java类与SQL语句之间的相互转 ...
- MyBatis动态sql之${}和#{}区别
前言 接触mybatis也是在今年步入社会之后,想想也半年多了,缺没时间去系统的学习,只知道大概,也是惭愧. 不知道有多少刚毕业的同学和我一样,到现在还没仔仔细细去了解你每天都会见到使用到的框 ...
- 【面试普通人VS高手系列】说一说Mybatis里面的缓存机制
一个工作了 5年的程序员,在私信里面不断向我诉苦. 他说,他用了Mybatis这么久,怎么滴也算是精通Mybatis了吧. 结果竟然在Mybatis这个面试题上翻车了! 真的好烦! 好吧,我们今天来看 ...
- mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句
mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:1. if 语句 (简单的条件判断)2. c ...
- 9.mybatis动态SQL标签的用法
mybatis动态SQL标签的用法 动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么 ...
- 自己动手实现mybatis动态sql
发现要坚持写博客真的是一件很困难的事情,各种原因都会导致顾不上博客.本来打算写自己动手实现orm,看看时间,还是先实现一个动态sql,下次有时间再补上orm完整的实现吧. 用过mybatis的人,估计 ...
- Mybatis动态SQL单一基础类型参数用if标签
Mybatis动态SQL单一基础类型参数用if标签时,test中应该用 _parameter,如: 1 2 3 4 5 6 <select id="selectByName" ...
- 超全MyBatis动态SQL详解!( 看完SQL爽多了)
MyBatis 令人喜欢的一大特性就是动态 SQL. 在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的. MyBatis 动态 SQL 的出现, 解决了这个麻烦. My ...
- Mybatis动态SQL简单了解 Mybatis简介(四)
动态SQL概况 MyBatis 的强大特性之一便是它的动态 SQL 在Java开发中经常遇到条件判断,比如: if(x>0){ //执行一些逻辑........ } Mybatis应用中,S ...
- mybatis 动态sql和参数
mybatis 动态sql 名词解析 OGNL表达式 OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性, ...
随机推荐
- 关于hibernate的缓存使用(转)
原文链接:http://blog.csdn.net/woshichenxu/article/details/586361#t0 1. 关于hibernate缓存的问题: 1.1.1. ...
- 关于position
一.position 一)语法: 看了那么久的语法,终于到了讲正题的时间了. 二)定位 1.相对定位:相对元素自己在没有定位之前的位置进行位移,元素仍然保留还没有原来的位置. 特性: 1)不脱离文档流 ...
- vscode 开发.net core 从安装到部署 教程详解
一:环境准备: windows系统需要 win7 sp1 / windows 8 / windows 2008 r2 sp1 / windows10: 其他版本的windows系统在安装.NET C ...
- [技术] 如何正确食用cnblogs的CSS定制
用过cnblogs的估计都知道cnblogs提供了相对比较开放的个性化选项,其中最为突出的估计就是页面CSS定制了.但是没学过Web前端的人可能并不会用这个东西... 所以我打算在此分享一些定制CSS ...
- 聊聊synchronized的锁问题
本文不会特别深入细致地讨论synchronized,只是做一个通俗易懂的说明,以及看清一类问题的本质,希望能给大家一点启发. 问题描述 有一个类A,提供了三个方法.分别是静态同步方法,非静态同步方法, ...
- hdu 6047 Maximum Sequence(贪心)
Description Steph is extremely obsessed with "sequence problems" that are usually seen on ...
- HAproxy部署配置
HAproxy部署配置 拓扑图 说明: haproxy服务器IP:172.16.253.200/16 (外网).192.168.29.140/24(内网) 博客服务器组IP:192.168.29.13 ...
- UIButton防止被重复点击
一.避免屏幕内多个 UIButton 被重复点击 1.在 AppDelegate 中添加[[UIButton appearance] setExclusiveTouch:YES]; 2.button. ...
- HDU字符串基础题(1020,1039,1062,1088,1161,1200,2017)
并不是很精简,随便改改A过了就没有再简化了. 1020. Problem Description Given a string containing only 'A' - 'Z', we could ...
- html5 mdn一些精彩的案例
https://developer.mozilla.org/zh_CN/docs/Games/Examples