Mybatis如何使用ognl表达式实现动态sql
作者:张财华 发布时间:2021-06-22 03:34:49
本文讲述在mybatis中如何使用ognl表达式实现动态组装sql语句
新建Users实体类:
public class Users {
private Integer uid;
private String userName;
private String tel;
//添加上面私有字段的get、set方法
}
新建一个Dao接口类,mybatis配置文件在配置namespace属性时需要加入这个类的完整类名,找到这个类里的方法执行:
public interface UserDao {
/**
* 依据userName查询用户信息
* @param user
* @return
*/
List<Users> listUser(Users user);
/**
* 动态选择条件
* @param user
* @return
*/
List<Users> listUser2(Users user);
/**
* 动态范围查询
* @param uids
* @return
*/
List<Users> listUser3(Integer[] uids);
/**
* 动态更新用户信息
* @param user
*/
void updateUser(Users user);
/**
* 批量添加
* @param list
*/
void addBatch(List<Users> list);
/**
* 批量删除
* @param ids
*/
void deleteBatch(int[] ids);
/**
* 批量更新
* @param list
*/
void updateBatch1(List<Users> list);
/**
* 批量更新
* @param list
*/
void updateBatch2(List<Users> list);
}
新建mybatis的配置文件(下面代码可以作为mybatis配置文件的模板,这里的namespace属性可以设置为上面的dao类的完整类名):
<?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指定Dao接口的完整类名,
因为mybatis在解析的时候要根据这个类名找到相应dao方法执行 --><mapper namespace=""> </mapper>
在mybatis配置文件中写一条条件查询sql语句:
<!-- 动态查询(使用if拼接条件,适用于多选多的形式) -->
<select id="listUser" parameterType="users" resultMap="userMap">
select u_id, u_name, u_tel from user_info4 user_info
<where>
<if test="userName != null and userName !=''">
u_name = #{userName}
</if>
<if test="tel != null and tel !=''">
and u_tel = #{tel}
</if>
</where>
</select>
这里使用了where和if标签,<where></where>意思就是sql语句中的where,当然,where直接在sql中写出来也可以,<if></if>标签就是条件判断,test属性中写条件语句,如果test中的条件语句为true,那么标签中的sql语句就会拼接到上面的sql语句中,所以这条sql语句的意思就是如果传过来的Users对象中,userName字段不为null,或字段值不为空,那么就添加一个对userName的查询,tel也是如此。
注意:在对tel字段的判断时,标签中的sql语句前加了一个and,如果前一条判断为false,那么mybatis会自动将and关键字删除。
<!-- 动态查询(使用choose选择条件,适用于多选一) -->
<select id="listUser2" parameterType="users" resultMap="userMap">
select u_id, u_name, u_tel from user_info4
<choose>
<when test="userName != null and userName != ''">
where u_name = #{userName}
</when>
<when test="tel != null and tel != ''">
where u_tel = #{tel}
</when>
<otherwise>
order by u_id desc
</otherwise>
</choose>
</select>
这里使用的是choose-when-otherwise标签,有点类似于java中的switch-case-default选择条件语句,相比于if标签,这里只能选择一个,即多选一。
在这条sql语句中,会按顺序判断when子句,如果所有的when子句都为false,则会执行otherwise子句中的sql语句。
<!-- 动态查询(使用foreach范围查询,适用于in和or语句) -->
<!-- int[] ids = new int[]{1,2,3,4}; -->
<select id="listUser3" parameterType="collection" resultMap="userMap">
select u_id, u_name, u_tel from user_info4
<where>
u_id in
<if test="array != null">
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
</where>
</select>
foreach标签适用于范围查询(in和or语句),如遍历一个id集合,查询出集合中所有id对应的用户。在foreach标签中,collection属性指定需要遍历的集合的名称,这里只有一个参数,所以可以随意取;item指定遍历的每一项的别名,open指定在遍历前需要加上的内容,separator指定每遍历一个后加上的内容,close指定遍历完后需要加上的内容,如遍历上面的ids集合,那么最终得到的内容就是 (1,2,3,4) 。
<!-- 动态更新(使用set动态更新字段) -->
<update id="updateUser" parameterType="users" >
update user_info4
<trim prefix="set" suffixOverrides=",">
<if test="userName != null and userName != ''">
u_name = #{userName},
</if>
<if test="tel != null and tel != ''">
u_tel = #{tel}
</if>
</trim>
<!-- where u_id = #{uid} -->
<where>
u_id = #{uid}
</where>
</update>
trim标签用于动态设值,例如在更新数据时,可以动态将改变的字段设置。在trim标签中,prefix属性表示在更新字段之前添加set关键字,suffixOverrides表示将最后一个更新字段的逗号替换成suffix指定的空格符,如果不指定suffix默认就是空格。
<!-- 批量添加,利用sql的特性 -->
<insert id="addBatch" parameterType="list">
insert into user_info4(u_id, u_name, u_tel) values
<foreach collection="list" item="user" separator=",">
(#{user.uid}, #{user.userName}, #{user.tel})
</foreach>
</insert>
foreach标签不仅可以用于范围查询,还可以遍历集合用于批量添加。
因为可以利用sql的特性,例如:insert into user_info4(u_name, u_tel) values('', ''), ('', ''), ('', '');这样执行这条sql语句就可以实现批量添加。
<!-- 批量更新1,这一种方式兼容性较好,当数据量大时 -->
<update id="updateBatch1" parameterType="list">
<foreach collection="list" item="user" separator=";">
update user_info4
<set>
u_name = #{user.userName}
</set>
where u_id = #{user.uid}
</foreach>
</update>
foreach还可以用于遍历出多条sql语句,使得一次可以执行多条sql,当然,如果需要MySql执行多条批量操作时,需要开启批量查询功能,即在MySql的url中加入 allowMultiQueries=true 。
<!-- 批量更新2,使用MySQL的case when语句 -->
<update id="updateBatch2" parameterType="list">
update user_info4 set u_name = case u_id
<foreach collection="list" item="user" separator=" ">
when #{user.uid} then #{user.userName}
</foreach>
end
where u_id in
<foreach collection="list" item="user" open="(" close=")" separator=",">
#{user.uid}
</foreach>
</update>
这里使用的是MySql中的case when语句来更新的,基本语法:
update user_info4 set u_name = case u_id
when 3 then '游客1'
when 4 then '游客2'
end
where u_id in(3,4);
Mybatis中的ognl使用总结
经常在写mapper中用到一些OGNL,但是没怎么总结,使用方法一直模模糊糊的。抽点时间,查了别人的blog,做个简单的总结
1.概念
OGNL,Object Graph Navigation Language,是一种强大的表达式语言,网上搜索这个概念,多是和structs有关的。但是在mybatis中OGNL应用很广的;
2.基本参数
Mybatis中常用的OGNL表达式有以下:
e1 or e2
e1 and e2
e1 == e2,e1 eq e2
e1 != e2,e1 neq e2
e1 lt e2:小于
e1 lte e2:小于等于,其他gt(大于),gte(大于等于)
e1 in e2
e1 not in e2
e1 + e2,e1 * e2,e1/e2,e1 - e2,e1%e2
!e,not e:非,求反
e.method(args)调用对象方法
e.property对象属性值
e1[ e2 ]按索引取值,List,数组和Map
@class@method(args)调用类的静态方法
@class@field调用类的静态字段值
更加详细的介绍可以参考官网的介绍:https://commons.apache.org/proper/commons-ognl/language-guide.html
在一定意义上说,mybatis中的动态sql也是基于OGNL表达式的。其中常用的元素有如下几种:
if
choose(when,otherwise)
trim
where
set
foreach
3.应用;
OGNL在mybatis中的应用,主要有两种;
1)动态SQL表达式;
举个栗子:
<code class="language-xml hljs has-numbering"><span class="hljs-tag"><<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"demo1"</span> <span class="hljs-attribute">...</span>></span>
</code><pre name="code" class="prettyprint"><code class="language-xml hljs has-numbering"> select id, name from users
<span class="hljs-tag"><<span class="hljs-title">bind</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"nameLike"</span> <span class="hljs-attribute">value</span>=<span class="hljs-value">"'%' + name + '%'"</span>/></span>
<span class="hljs-tag"><<span class="hljs-title">where</span>></span>
<span class="hljs-tag"><<span class="hljs-title">if</span> <span class="hljs-attribute">test</span>=<span class="hljs-value">"name != null and name != ''"</span>></span>
name like '${nameLike}'
<span class="hljs-tag"></<span class="hljs-title">if</span>></span>
<span class="hljs-tag"></<span class="hljs-title">where</span>></span>
<span class="hljs-tag"></<span class="hljs-title">select</span>></span></code>
其中的bind中的value值会使用OGNL计算,ps,其中bind的参数调用只能用$获取;
2)${param}参数中
<code class="language-xml hljs has-numbering"><span class="hljs-tag"><<span class="hljs-title">select</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"demo2"</span> <span class="hljs-attribute">...</span>></span>
select id,name from users
<span class="hljs-tag"><<span class="hljs-title">where</span>></span>
<span class="hljs-tag"><<span class="hljs-title">if</span> <span class="hljs-attribute">test</span>=<span class="hljs-value">"name != null and name != ''"</span>></span>
name like '${'%' + name + '%'}'
<span class="hljs-tag"></<span class="hljs-title">if</span>></span>
<span class="hljs-tag"></<span class="hljs-title">where</span>></span>
<span class="hljs-tag"></<span class="hljs-title">select</span>></span></code>
此处写的是 ${'%' + name + '%'},而不是 %${name}%,这两种方式的结果一样,但是处理过程不一样。
ps,说明一下#和$的区别:${} 为原样输出,你传什么,sql里就填入什么,比如有引号它也会原样填到sql里。#{} 会使用 PreparedStatement,变量处用 ? 代替。
在能使用 #{} 尽量使用它吧,可以防止sql注入。
以下是一个OGNL的调用静态方法的示例:
<select id="getRecentQuestionTitle" parameterType="java.lang.String" resultType="java.lang.String">
select title from song_question where questionState = #{value}
<if test="@Ognl@isSolve(value[0],0)">
order by questionTime desc
</if>
<if test="@Ognl@isSolve(value[0],1)">
order by answerTime desc
</if>
limit 0,1
</select>
静态方法如下:
public static boolean isSolve(Object o,String soleState){
if(o == null)
return false;
String str = null;
if(o instanceof String[]){
String[]objects = (String[])o;
str = objects[0];
}else if(o instanceof Character){
Character c = (Character) o;
str = Character.toString(c);
}
if(StringUtils.equals(str, soleState))
return true;
return false;
}
如果值为0,则order by questionTime desc 根据字段questionTime排序。
如果值为1,则order by answerTime desc根据字段answerTime排序。
来源:https://www.cnblogs.com/zhangcaihua/p/12899061.html


猜你喜欢
- 这个问题困扰了很久,有些类不是controller在使用autowired注入的类显示为空,找到网上的方法是在类初始化时主动注入被Autow
- 前言在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 if-else/switch-case 去
- Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。程序员在使用这些 API 的时候,不需
- 简介:本文将帮助您使用 Spring Boot 创建简单的 REST 服务。你将学习什么是 REST 服务?如何使用 Spring Init
- 本文实例讲述了C++编写DLL动态链接库的步骤与实现方法。分享给大家供大家参考,具体如下:在写C++程序时,时常需要将一个class写成DL
- 常用的Dialog有确认对话框,单选按钮对话框,多选按钮对话框,复选按钮对话框另外还有自定义的对话框AlertDialog的常用方法setT
- 引言 在c#中,可能大多数人针对于多线程之间的通讯,是熟能生巧,对于AsyncLocal 和Thre
- 第 1 步:将这个 Spring Boot 项目的打包方式设置为 war。<packaging>war</packagin
- 为了解决以下两个问题:1、单JAR包应用查看日志需要的时候如果需要远程访问服务器登录查看日志,那样相对比较麻烦2、生产环境为了解决BUG需要
- SpringCloud是分布式微服务架构的一站式解决方案,十多种微服务架构落地技术的集合体,俗称微服务全家桶SpringCloud和Spri
- 前言C# 时间戳与 标准时间的转其实不难,但需要注意下,基准时间的问题。格林威治时间起点: 1970 年 1 月 1 日的 00:00:00
- Java中自动生成构造方法详解每个类在没有声明构造方法的前提下,会自动生成一个不带参数的构造方法,如果类一但声明有构造方法,就不会产生了.证
- 项目中最近用到各种图表,本来打算用第三方的,例如MPAndroid,这是一个十分强大的图表库,应用起来十分方便,但是最终发现和设计不太一样,
- HandlerThread 顾名思义就是一种可以使用 Handler 的 Thread。日常开发中我们经常会通过创建一个 Thread 去执
- 本文大纲本文章将要介绍的内容有以下几点,读者朋友也可先自行思考一下相关问题:线程中断 interrupt 方法怎么理解,意思就是线程中断了吗
- 序言在flutter开发中,我们使用 bloc 框架,基于状态变更进行响应式开发。本篇文章,小轰将 bloc 核心业务块进行拆解简化,聊一聊
- 内网用户或 * 的用户使用 using System.IO; using System.Net; public string get_ht
- 静默安装就是偷偷的把一个应用安装到手机上,就是屏蔽确认框,通过反射只能写个主要的代码,这个是在linux编译用到,因为静默安装需要调用系统服
- < application /> :应用的声明。 这个元素包含了子元素,这些子元素声明了应用的组件,元素的属性将会影响应用下的所
- 本文实例讲述了JDBC基础知识与技巧。分享给大家供大家参考。具体分析如下:1.什么是JDBC?通俗来讲JDBC技术就是通过java程序来发送