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 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 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 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 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 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 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 parameterType='list'>update user_info4 set u_name = case u_id<foreach collection='list' item='user' separator=' '> when #{user.uid} then #{user.userName}</foreach>endwhere 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_idwhen 3 then ’游客1’when 4 then ’游客2’endwhere 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 foreach3.应用;
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 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排序。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持好吧啦网。
相关文章: