MyBatis(4)动态sql语法

mac2026-03-19  2

目录

一 OGNL表达式常规用法集合用法 二 if三 where四 trim五 choose六 set (主要用于更新时)七 foreach单参数List的类型数组类型的参数Map类型的参数 八 bind九 sql片段十 批量保存MySQLOracle 十一 内置参数参考

一 OGNL表达式

OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对Java对象图进行导航。类似于我们的EL,SpEL等

OGNL表达式的基本单位是"导航链",一般导航链由如下几个部分组成: (1)属性名称(property) (2)方法调用(method invoke) (3)数组元素 所有的OGNL表达式都基于当前对象的上下文来完成求值运算,链的前面部分的结果将作为后面求值的上下文。例如:names[0].length()。

常规用法

访问对象属性:person.name调用方法: person.getName()调用静态属性/方法:@java.lang.Math@PI ;@java.util.UUID@randomUUID()调用构造方法:new com.atguigu.bean.Person(‘admin’).name运算符: +,-*,/,%逻辑运算符: in,not in,>,>=,<,<=,==,!= 注意:xml中特殊符号如”,>,<等这些都需要使用转义字符

集合用法

类型伪属性伪属性对应的 Java 方法List、 Set、 Mapsize、 isEmptyList/Set/Map.size(),List/Set/Map.isEmpty()List、 SetiteratorList.iterator()、 Set.iterator()Mapkeys、 valuesMap.keySet()、 Map.values()Iteratornext、 hasNextIterator.next()、 Iterator.hasNext()

二 if

<select id="findUserByIf" resultType="com.zyc.entity.User" parameterType="com.zyc.entity.User"> select id,username ,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex ,address from t_user where 1 = 1 <if test="id != null"> and id = #{id} </if> <if test="username != null"> and username = #{username} </if> </select>

三 where

主要是用来简化sql语句中where条件判断的,能智能的处理 and or条件 mybatis使用where标签来将所有的查询条件包括在内(会自动加where关键)。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉(where只会去掉第一个多出来的and或者or) 总结 配合if,剩下无用的 1=1

<select id="findUserByWhere" resultType="com.zyc.entity.User" parameterType="com.zyc.entity.User"> select id,username ,DATE_FORMAT(birthday,'%Y-%m-%d')birthday,sex ,address from t_user <where> <if test="id != null"> and id = #{id} </if> <if test="username != null"> and username = #{username} </if> </where> </select>

四 trim

后面多出的and或者or where标签不能解决

prefix="" 前缀:trim标签体中是整个字符串拼串 后的结果。prefix给拼串后的整个字符串加一个前缀prefixOverrides="" 前缀覆盖: 去掉整个字符串前面多余的字符suffix="" 后缀:suffix给拼串后的整个字符串加一个后缀suffixOverrides="" 后缀覆盖:去掉整个字符串后面多余的字符

这些属性里面可以写一些sql语句或表达式

prefixoverride="AND |OR"suffix=" where id = #{id} " <select id="dynamicTrimTest" parameterType="Blog" resultType="Blog"> select * from t_blog <trim prefix="where" prefixOverrides="and |or"> <if test="title != null"> title = #{title} </if> <if test="content != null"> and content = #{content} </if> <if test="owner != null"> or owner = #{owner} </if> </trim> </select>

五 choose

相当于java 语言中的 switch ,与 jstl 中的choose 很类似

<select id="dynamicChooseTest" parameterType="Blog" resultType="Blog"> select * from t_blog where 1 = 1 <choose> <when test="title != null"> and title = #{title} </when> <when test="content != null"> and content = #{content} </when> <otherwise> and owner = "owner1" </otherwise> </choose> </select>

当when中有条件满足的时候,就会跳出choose,即所有的when和otherwise条件中,只有一个会输出,当所有的我很条件都不满足的时候就输出otherwise中的内容

六 set (主要用于更新时)

set元素主要是用在更新操作的时候,它的主要功能和where元素其实是差不多的,主要是在包含的语句前输出一个set,然后如果包含的语句是以逗号结束的话将会把该逗号忽略(去掉),如果set包含的内容为空的话则会出错。有了set元素我们就可以动态的更新那些修改了的字段。 非NULL更新

<!--public void updateEmp(Employee employee); --> <update id="updateEmp"> <!-- Set标签的使用 --> update tbl_employee <set> <if test="lastName!=null"> last_name=#{lastName}, </if> <if test="email!=null"> email=#{email}, </if> <if test="gender!=null"> gender=#{gender} </if> </set> where id=#{id} <!-- Trim:更新拼串 update tbl_employee <trim prefix="set" suffixOverrides=","> <if test="lastName!=null"> last_name=#{lastName}, </if> <if test="email!=null"> email=#{email}, </if> <if test="gender!=null"> gender=#{gender} </if> </trim> where id=#{id} --> </update>

七 foreach

在实现 mybatis in 语句查询时特别有用 foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。 (1)item表示集合中每一个元素进行迭代时的别名。 (2)index 索引。遍历list的时候是index就是索引,item就是当前值;遍历map的时候index表示的就是map的key,item就是map的值 (3)open 遍历出所有结果拼接一个开始的字符 (4)separator 表示在每次进行迭代之间以什么符号作为分隔符。 (5)close 遍历出所有结果拼接一个结束的字符 (6)collection 指定要遍历的集合:list类型的参数会特殊处理封装在map中,map的key就叫list


在使用foreach的时候·最关键·的也是·最容易出错·的就是collection属性·,该属性是·必须指定·的,但是在·不同情况下·,该属性的值是不一样的,主要有一下3种情况: (1)如果传入的是单参数且参数类型是一个List的时候,collection属性值为list。对应上面的特殊处理 (2)如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array 也是mybatis处理的 (3)如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key。

单参数List的类型

public List<User> dynamicForeachTest(List<Integer> ids) <select id="dynamicForeachTest" resultType="com.mybatis.entity.User"> select * from t_user where id in <foreach collection="list" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select>

数组类型的参数

<select id="dynamicForeach2Test" resultType="com.mybatis.entity.User"> select * from t_user where id in <foreach collection="array" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select>

Map类型的参数

<select id="dynamicForeach3Test" resultType="com.mybatis.entity.User"> select * from t_user where username like '%${username}%' and id in <foreach collection="ids" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select> public List<User> dynamicForeach3Test(Map<String, Object> params);

调用demo

List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(2); ids.add(6); Map map =new HashMap(); map.put("username", "小"); map.put("ids", ids); List<User> userList = mapper.dynamicForeach3Test(map); System.out.println("------------------------"); for (User user : userList){ System.out.println(user); }

八 bind

bind标签的两个属性都是必选项,name为绑定到上下文的变量名,value为OGNL表达式,创建一个bind标签后,就可以在下面直接使用了。 使用bind拼接字符串不仅可以避免因更换数据库而修改SQL,也能预防SQL注入

<select id="selectSysUserByAdvancedCondition" resultType="com.artisan.mybatis.xml.domain.SysUser"> SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a <where> <if test="userName != null and userName != '' "> <!-- and user_name like concat('%',#{userName},'%') --> <bind name="userNameLike" value=" '%' + userName + '%' "/> and user_name like #{userNameLike} </if> <if test="userEmail != null and userEmail != '' "> and user_email = #{userEmail} </if> </where> </select>

九 sql片段

抽取可重用的sql片段。方便后面引用

·sql抽取·:·经·常将要查询的列名,或者插入用的·列名·抽取出来方便引用include来引用已经抽取的sql:include还可以自定义一些property,sql标签内部就能使用自定义的属性 include-property:取值的正确方式${prop}, #{不能使用这种方式} <sql id="insertColumn"> <if test="_databaseId=='oracle'"> employee_id,last_name,email </if> <if test="_databaseId=='mysql'"> last_name,email,gender,d_id </if> </sql>

十 批量保存

MySQL

两种方式

<!-- 批量保存 --> <!--public void addEmps(@Param("emps")List<Employee> emps); --> <!--MySQL下批量保存:可以foreach遍历 mysql支持values(),(),()语法--> <insert id="addEmps"> insert into tbl_employee( <include refid="insertColumn"></include> ) values <foreach collection="emps" item="emp" separator=","> (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id}) </foreach> </insert> <!-- 这种方式需要数据库连接属性allowMultiQueries=true; 这种分号分隔多个sql可以用于其他的批量操作(删除,修改) --> <insert id="addEmps"> <foreach collection="emps" item="emp" separator=";"> insert into tbl_employee(last_name,email,gender,d_id) values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id}) </foreach> </insert>

Oracle

<!-- Oracle数据库批量保存: Oracle不支持values(),(),() Oracle支持的批量方式 1、多个insert放在begin - end里面 begin insert into employees(employee_id,last_name,email) values(employees_seq.nextval,'test_001','test_001@atguigu.com'); insert into employees(employee_id,last_name,email) values(employees_seq.nextval,'test_002','test_002@atguigu.com'); end; 2、利用中间表: insert into employees(employee_id,last_name,email) select employees_seq.nextval,lastName,email from( select 'test_a_01' lastName,'test_a_e01' email from dual union select 'test_a_02' lastName,'test_a_e02' email from dual union select 'test_a_03' lastName,'test_a_e03' email from dual ) --> <insert id="addEmps" databaseId="oracle"> <!-- oracle第一种批量方式 --> <!-- <foreach collection="emps" item="emp" open="begin" close="end;"> insert into employees(employee_id,last_name,email) values(employees_seq.nextval,#{emp.lastName},#{emp.email}); </foreach> --> <!-- oracle第二种批量方式 --> insert into employees( <!-- 引用外部定义的sql --> <include refid="insertColumn"> <property name="testColomn" value="abc"/> </include> ) <foreach collection="emps" item="emp" separator="union" open="select employees_seq.nextval,lastName,email from(" close=")"> select #{emp.lastName} lastName,#{emp.email} email from dual </foreach> </insert>

十一 内置参数

不只是方法传递过来的参数可以被用来判断,取值等操作 mybatis默认还有两个内置参数:

_parameter:代表整个参数 单个参数:_parameter就是这个参数 多个参数:参数会被封装为一个map;_parameter就是代表这个map_databaseId:如果配置了databaseIdProvider标签(主配置文件中)。 _databaseId就是代表当前数据库的别名 <select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee"> <!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 --> <bind name="_lastName" value="'%'+lastName+'%'"/> <if test="_databaseId=='mysql'"> select * from tbl_employee <if test="_parameter!=null"> where last_name like #{lastName} </if> </if> <if test="_databaseId=='oracle'"> select * from employees <if test="_parameter!=null"> where last_name like #{_parameter.lastName} </if> </if> </select>

参考

Mybatis学习总结(五)——动态sql尚硅谷mybatis教程资料MyBatis-15MyBatis动态SQL之【bind】
最新回复(0)