MyBatis - 4.动态SQL
- 动态 SQL是MyBatis强大特性之一。极大的简化我们拼装SQL的操作。
- 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。
- MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。

1.if
新建接口
public interface IemployeeMapperDynamicSQL {
public List<employee> getEmpsByConditionIf(employee emp);
}
新建Mapper IemployeeMapperDynamicSQL.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="com.tangge.Mapper.IemployeeMapperDynamicSQL">
<!--
if
choose (when, otherwise)
trim (where, set)
foreach
-->
<!--public List<employee> getEmpsByConditionIf(employee emp);-->
<select id="getEmpsByConditionIf" resultType="com.tangge.model.employee">
select * from tbl_employee WHERE 1=1
<if test="id != 0">
and id=#{id}
</if>
<!--QGNL中的(和):and 和 && ,XML不支持&&,所以可以写成 &&-->
<if test="lastName != null && lastName != ''">
and last_name like #{lastName}
</if>
<!--QGNL中的(或):or 和 || -->
<if test=" gender ==0 || gender == 1">
and gender = #{gender}
</if>
<if test="email != null">
and email=#{email}
</if>
</select>
</mapper>
---->【测试】:
public static void getEmpsByConditionIf() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
IemployeeMapperDynamicSQL mapper = session.getMapper(IemployeeMapperDynamicSQL.class);
employee employee = new employee(0,"%i%",null,null);
List<employee> employees = mapper.getEmpsByConditionIf(employee);
System.out.println(employees);
/**
* 结果:
* [employee{id=1, lastName='null', email='tom@guigu.com', gender=0, dept=null},
* employee{id=5, lastName='null', email='lily@xwf.com', gender=1, dept=null}]
*/
} finally {
session.close();
}
}
2.choose
类似带了 breack 的 swicth-case
<select id="getEmpsByConditionChoose" resultType="com.tangge.model.employee">
select * from tbl_employee
<where>
<choose>
<when test="id != 0">
id=#{id}
</when>
<when test="lastName != null && lastName != ''">
last_name like #{lastName}
</when>
<when test="email != null">
email=#{email}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</where>
</select>
3.Trim
如果条件后面加and,最后生成的SQL条件也有一条and,我们需要删除掉。
使用 <trim>标签
<select id="getEmpsByConditionTrim" resultType="com.tangge.model.employee">
select * from tbl_employee
<!--
trim:
- prefix:前缀
- prefixOverrides:前缀覆盖
- suffix:后缀
- prefixOverrides:后缀覆盖
-->
<trim prefix="where" suffixOverrides="and">
<if test="id != 0">
id=#{id} and
</if>
<!--QGNL中的(和):and 和 && ,XML不支持&&,所以可以写成 &&-->
<if test="lastName != null && lastName != ''">
last_name like #{lastName} and
</if>
<!--QGNL中的(或):or 和 || -->
<if test=" gender ==0 || gender == 1">
gender = #{gender} and
</if>
<if test="email != null">
email=#{email} and
</if>
</trim>
</select>
3.1 where
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
3.2.set(封装修改条件)
<!--
set标签:
set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。
(因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)
-->
<update id="updateEmp" >
UPDATE tbl_employee
<set>
<if test="lastName != null && lastName != ''">
last_name = #{lastName},
</if>
<!--QGNL中的(或):or 和 || -->
<if test="gender ==0 || gender == 1">
gender = #{gender},
</if>
<if test="email != null">
email=#{email},
</if>
</set>
<where>
id = #{id}
</where>
</update>
若你对 set 元素等价的自定义 trim 元素的代码感兴趣,那这就是它的真面目:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
4.foreach
动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:
定义个接口
public List<employee> getEmpsByConditionForeach(List<Integer> list1);
Mapper
<select id="getEmpsByConditionForeach" resultType="com.tangge.model.employee">
select * from tbl_employee WHERE id in
<!--
foreach:
- collection:指定要遍历的集合:list类型的参数会封装在map中,map的key就叫list
- item:将遍历出的元素赋值给指定变量
#{变量名} 当前遍历的元素
- separator:每个元素之间的分隔符
- open:开始的字符前缀
- close:结束字符后缀
- index:
- list: index是list的索引,item是当前值
- map: index是map的key,item是map的value
-->
<foreach collection="list" item="item_id" separator="," open="(" close=")">
#{item_id}
</foreach>
</select>
---->【测试】:
public static void getEmpsByConditionForeach() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
IemployeeMapperDynamicSQL mapper = session.getMapper(IemployeeMapperDynamicSQL.class);
List<Integer> list1 = new ArrayList<>();
list1.add(5);
list1.add(6);
List<employee> rows = mapper.getEmpsByConditionForeach(list1);
//执行的SQL:select * from tbl_employee WHERE id in ( 5 , 6 )
System.out.println(rows);
} finally {
session.close();
}
}
4.1 批量插入使用foreach
接口声明:
public boolean addEmpList(@Param("emps") List<employee> employees);
Mapper
<!--批量插入-->
<!-- public boolean addEmpList(@Param("emps") List<employee> employees);-->
<insert id="addEmpList">
INSERT INTO tbl_employee(last_name,gender,email,dept_id) VALUES
<foreach collection="emps" item="item" separator="," >
(#{item.lastName},#{item.gender},#{item.email},#{item.dept.departmentId})
</foreach>
</insert>
---->【测试】:
public static void addEmpList() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
IemployeeMapperDynamicSQL mapper = session.getMapper(IemployeeMapperDynamicSQL.class);
employee employee = new employee("wwa","sdas@sasa",null);
employee employee1 = new employee("wwc","sdas@sasa",null);
List<employee> emps = new ArrayList<>();
emps.add(employee);
emps.add(employee1);
boolean rows = mapper.addEmpList(emps);
System.out.println(rows);
} finally {
session.close();
}
}
5.内置参数:_parameter 与 _databaseId
public List<employee> getEmpsInnerParameter(employee emp);
配置
<!--
两个内置参数:
- _parameter:代表整个参数
* 单个参数:_parameter就是整个参数
* 多个参数:参数封装一个map,_parameter就代表真个map
- _databaseId:如果config xml配置了databaseIdProvider标签。
* _databaseId代表当前数据库的别名oracle
-->
<!--public List<employee> getEmpsInnerParameter(employee emp);-->
<select id="getEmpsInnerParameter" resultType="com.tangge.model.employee">
<if test="_databaseId=='mysql'">
select * from tbl_employee
<if test="_parameter!=null">
WHERE last_name LIKE #{_parameter.lastName}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from employees
</if>
</select>
---->【测试】:
public static void getEmpsInnerParameter() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
try {
IemployeeMapperDynamicSQL mapper = session.getMapper(IemployeeMapperDynamicSQL.class);
employee employee = new employee(0,"%w%",null,null);
List<employee> employees = mapper.getEmpsInnerParameter(employee);
System.out.println(employees);
} finally {
session.close();
}
}
结果:
DEBUG 08-28 15:46:43,167 ==> Preparing: select * from tbl_employee WHERE last_name LIKE ? (BaseJdbcLogger.java:139)
DEBUG 08-28 15:46:43,192 ==> Parameters: %w%(String) (BaseJdbcLogger.java:139)
DEBUG 08-28 15:46:43,221 <== Total: 3 (BaseJdbcLogger.java:139)
[
employee{id=6, lastName='null', email='wewe@qq.com', gender=1, dept=null},
employee{id=7, lastName='null', email='sdas@sasa', gender=null, dept=null},
employee{id=8, lastName='null', email='sdas@sasa', gender=null, dept=null}
]
6.bind (OGNL 表达式绑定)
上面传参 %w%
employee employee = new employee(0,"%w%",null,null);
Mapper
<if test="_parameter!=null">
WHERE last_name LIKE #{_parameter.lastName}
</if>
然后输出的是
DEBUG 08-28 15:46:43,192 ==> Parameters: %w%(String)
---->【需求】::现在我们想要传入参数%w%变为w,%在Mapper里添加。
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文
<select id="getEmpsInnerParameter" resultType="com.tangge.model.employee">
<!--bind使用-->
<bind name="pattern" value="'%' + _parameter.lastName + '%'" />
<if test="_databaseId=='mysql'">
select * from tbl_employee
<if test="_parameter!=null">
WHERE last_name LIKE #{pattern}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from employees
</if>
</select>
7.sql 和 include(抽取可重用的SQL片段)
<select id="getEmpsInnerParameter" resultType="com.tangge.model.employee">
<bind name="pattern" value="'%' + _parameter.lastName + '%'" />
<if test="_databaseId=='mysql'">
<!--
引用外部的SQL
- property:自定义属性
这里${abc} 值 tbl_employee,可以在<sql>里运用
-->
<include refid="employee">
<property name="abc" value="tbl_employee"/>
</include>
<if test="_parameter!=null">
WHERE last_name LIKE #{pattern}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from employees
</if>
</select>
<!--
抽取可重用的SQL片段,方便引用
- <sql>抽取:经常查询的列名,或者插入用的列名抽取出来方便引用
- <include>:引用抽取的SQL
- <include>还可以定义<property>,sql内部标签可以使用 ${prop}
-->
<sql id="employee">
select * from ${abc}
</sql>
MyBatis - 4.动态SQL的更多相关文章
- MyBatis的动态SQL详解
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它 ...
- Mybatis解析动态sql原理分析
前言 废话不多说,直接进入文章. 我们在使用mybatis的时候,会在xml中编写sql语句. 比如这段动态sql代码: <update id="update" parame ...
- mybatis 使用动态SQL
RoleMapper.java public interface RoleMapper { public void add(Role role); public void update(Role ro ...
- MyBatis框架——动态SQL、缓存机制、逆向工程
MyBatis框架--动态SQL.缓存机制.逆向工程 一.Dynamic SQL 为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句.最常用的就是:where和if标签 1.参考 ...
- 使用Mybatis实现动态SQL(一)
使用Mybatis实现动态SQL 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 写在前面: *本章节适合有Mybatis基础者观看* 前置讲解 我现在写一个查询全部的 ...
- MyBatis探究-----动态SQL详解
1.if标签 接口中方法:public List<Employee> getEmpsByEmpProperties(Employee employee); XML中:where 1=1必不 ...
- mybatis中的.xml文件总结——mybatis的动态sql
resultMap resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功. 如果sql查询字段名和pojo的属性名不一致,可以通过re ...
- mybatis.5.动态SQL
1.动态SQL,解决关联sql字符串的问题,mybatis的动态sql基于OGNL表达式 if语句,在DeptMapper.xml增加如下语句; <select id="selectB ...
- MyBatis的动态SQL详解-各种标签使用
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...
- 利用MyBatis的动态SQL特性抽象统一SQL查询接口
1. SQL查询的统一抽象 MyBatis制动动态SQL的构造,利用动态SQL和自定义的参数Bean抽象,可以将绝大部分SQL查询抽象为一个统一接口,查询参数使用一个自定义bean继承Map,使用映射 ...
随机推荐
- Android 5.0以上Material Design 沉浸式状态栏
偶然在知乎上看到这个问题,Android 5.0 如何实现将布局的内容延伸到状态栏,之前也见过多个应用的这个功能,但是知乎上的答案却没有一个真正实现此功能的一类是把标题栏设置App主题颜色,一类是提取 ...
- Python笔记 【无序】 【三】
#打开文件 os.open(file, flags[, mode]); file -- 要打开的文件 flags -- 该参数可以是以下选项,多个使用 "|" 隔开: os.O_R ...
- HDOJ 1166 敌兵布阵 (线段树)
题目: Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Ti ...
- zookeeper安装教程
zookeeper 一.单机安装 1.1 下载 1.2 安装 1.3 配置 1.4 启动和停止 二.伪集群模式 2.1 zookeeper1配置 2.2 zookeeper2配置 2.3 zooke ...
- mac配置supervisor
mac配置supervisor 安装 brew install supervisor 启动 一种是手动 supervisord -c /usr/local/etc/supervisord.ini 让s ...
- hibernate框架学习之数据查询(HQL)
lHibernate共提供5种查询方式 •OID数据查询方式 •HQL数据查询方式 •QBC数据查询方式 •本地SQL查询方式 •OGN数据查询方式 OID数据查询方式 l前提:已经获取到了对象的OI ...
- 4-HTML Computer Code Elements
HTML Computer Code Elements Tag Description <code> Defines programming code <kbd> Define ...
- mysql:批量插入不同的UUID
INSERT INTO t_base_role_resource_ref (refID, roleID, resID, orgID, belongTo) SELECT uuid() AS refID, ...
- [MySQL]多表关联查询技巧
示例表A: author_id author_name 1 Kimmy 2 Abel 3 Bill 4 Berton 示例表B: book_id author_id start_date end_da ...
- 定制起始url(scrapy_redis)
爬虫:(在这里不用配置start_url,直接可以取redis里面取start_url,可以多个) from scrapy_redis.spiders import RedisSpider # cla ...