-
动态SQL【code that is executed dynamically】
1.为什么会有Mybatis动态SQL?
实际业务中一定会经常遇到按照很多查询条件进行查询的情况,比如京东根据不同的条件筛选商品。其中经常出现很多条件不取值的情况(只有单个或者几个条件进行查询),在后台应该如何完成最终的SQL语句呢?
如果采用
JDBC
进行处理,需要根据条件是否取值来进行SQL语句的拼接,一般情况下是使用StringBuilder
类及其append
方法实现,还是有些繁琐的,或者利用反射,比如:preparedStatement = connection.prepareStatement(sql);
//可能设置了查询的条件,所以需要参数设置
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i+1,args[i]);
}
resultSet = preparedStatement.executeQuery();
//根据字节码文件获取属性:
Field[] fields = clazz.getDeclaredFields();
//设置私有属性为可访问(注意:这个baseQuery方法不是很安全,是一种临时的解决办法)
for (Field field : fields) {
field.setAccessible(true);
}
//根据反射创建对象
while (resultSet.next()){
//创建实例
Object o = clazz.newInstance();
for (Field field : fields) {
//根据field获取属性的名称
String name = field.getName();
//根据field获取的属性名称,获取resultSet中的数据
Object data = resultSet.getObject(name);
//设置实例的属性值
field.set(o,data);
}如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
MyBatis在简化操作方法提出了动态SQL功能,将使用Java代码拼接SQL语句,改变为在XML映射文件中截止标签拼接SQL语句。相比而言,大大减少了代码量,更灵活、高度可配置、利于后期维护。
MyBatis中动态SQL是编写在
mapper.xml
中的,其语法和JSTL
类似,但是却是基于强大的OGNL
表达式实现的。MyBatis也可以在注解中配置SQL,但是由于注解功能受限,尤其是对于复杂的SQL语句,可读性很差,所以较少使用。
所以说了半天,动态SQL就是:
让我们在XML映射文件内,以标签的形式编写动态的SQL,完成逻辑判断和动态拼接SQL 的功能。
Mybatis 提供了 9 种动态 SQL 标签:
<if />
、<choose />
、<when />
、<otherwise />
、<trim />
、<where />
、<set />
、<foreach />
、<bind />
。2.常用的动态SQL的标签
准备环境
新建一个Maven项目(或者模块module)
Mybatis_pro04
在
pom.xml
中引入以下配置和依赖:<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>compile</scope>
</dependency>
</dependencies>引入配置和依赖之后,可以手动重新加载maven项目:
image-20221015114852004 注意:关于lombok的使用,需要安装Lombok插件(plugins)和引⼊Lombok依赖(pom.xml中)
(有些版本的IDEA可能比较抽风,需要手动加载,蔽日我的IDEA)
怎么验证加载有没有成功?
然后搭建项目结构:
【1】创建相关包和配置文件。(特别注意:resources目录下,包的创建必须一层一层,这个是IDEA的bug)
【2】书写配置文件:
jdbc.properties
(对于mysql8.0版本,下面的jdbc_url
最好这么写,否则会有无法避免的错误)jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc_username=你的数据库的用户名
jdbc_password=你的数据库的密码log4j.properties
版本1.2.17#定义全局日志级别调试阶段推荐debug
log4j.rootLogger=debug,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/xxx.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n如果版本是log4j2,则需要在resources文件下创建
log4j2.xml
,文件内容如下:<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
</Console>
<RollingFile name="RollingFile" filename="log/test.log"
filepattern="${logPath}/%d{YYYYMMddHHmmss}-fargo.log">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="20" />
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties" />
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
<!--默认每个实体类的别名是首字母小写的类名-->
<package name="com.bones.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc_driver}"/>
<property name="url" value="${jdbc_url}"/>
<property name="username" value="${jdbc_username}"/>
<property name="password" value="${jdbc_password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.bones.mapper.EmpMapper"/>
</mappers>
</configuration>其中
mappers
标签中书写mapper映射文件的路径(这里用的是基于接口的代理模式开发)typeAliases
标签为实体类的包com.bones.pojo
取了别名,为了在mapper映射文件中可以直接写实体类的别名(Emp—>emp,一般为小写)EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bones.mapper.EmpMapper">
</mapper>sql语句会逐渐丰富在这里面。
【3】准备实体类:
现在有的数据库表是:
结合lombok准备实体类代码:
package com.bones.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* @author : bones
* @version : 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp implements Serializable {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
}if标签
现在有数据库表
Emp
,根据用户传入的值进行查询(用户可能不会给出所有属性的所有的值)接口EmpMapper
package com.bones.mapper;
import com.bones.pojo.Emp;
import java.util.List;
/**
* @author : bones
* @version : 1.0
*/
public interface EmpMapper {
List<Emp> findByCondition(Emp emp);
}映射文件EmpMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bones.mapper.EmpMapper">
<!-- List<Emp> findByCondition(Emp emp);-->
<select id="findByCondition" resultType="emp">
select * from emp where 1=1
<if test="empno != null">
and empno = #{empno}
</if>
<if test="ename != null and ename != ''">
and ename = #{ename}
</if>
<if test="job != null and job != ''">
and ename = #{ename}
</if>
<if test="mgr != null">
and mgr = #{mgr}
</if>
<if test="hiredate != null">
and hiredate = #{hiredate}
</if>
<if test="sal != null">
and sal = #{sal}
</if>
<if test="comm != null">
and comm = #{comm}
</if>
<if test="deptno != null">
and deptno = #{deptno}
</if>
</select>
</mapper>测试代码:(junit测试)
package com.bones.test;
import com.bones.mapper.EmpMapper;
import com.bones.pojo.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author : bones
* @version : 1.0
*/
public class Test01 {
SqlSession sqlSession;
@Before
public void init(){
SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
InputStream resourceAsStream = null;
try {
resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory factory = ssfb.build(resourceAsStream);
sqlSession = factory.openSession();
}
@Test
public void testFindByCondition(){
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = new Emp(null, null, null, null, null, null, null, null);
List<Emp> empList = empMapper.findByCondition(emp);
empList.forEach(System.out::println);
}
@After
public void close(){
sqlSession.close();
}
}注意几点:
1.实体类尽量使用包装类作为数据类型,因为要判空。
2.lombok注解 的使用注意:
Lombok使⽤@Data可以⽣成类⾥⾯所有属性的getter/setter⽅法和无参构造方法。
比如我现在只是写了注解:
@Data
然后利用maven的生命周期,先clean再compile,查看target目录下的 字节码文件:其实除了类⾥⾯所有属性的getter/setter⽅法和无参构造方法之外,还有
equals
,canEqual
(相当于instanceof
),hashCode
,toString
等方法。但是如果注解中加入了
@Data
和@AllArgsConstructor
两个注解,奇妙的事发生了:这里
@Data
注解并没有生成无参构造方法。所以要在这种情况下使用无参构造器,是不可能 的。
而很多框架都会调用无参构造方法去创建对象,所以无参构造方法是必须 的。
此时必须显式声明出无参构造方法 ,即 加上注解
@NoArgsConstructor
.还要注意:我最近读到一篇文章https://mp.weixin.qq.com/s/wWoQQgVrJSjRVAg-oPQidw【Lombok 同时使用 @Data 和 @Builder 的巨坑,千万别乱用!】
在那篇文章中说Lombok同时使⽤
@Data
和@Builder
,构建无参构造器报错,其实也是上面我说的问题:如果同时使⽤@Data
和@Builder
的话,@Data
在有其他注解(@Builder
和@AllArgsConstructor
这两个注解)尽管⽣成了GET/SET⽅法,但是⽆参构造⽅法没有了,这显然是不能接受的.于是我想到了,在我的实体类中不用
@AllArgsConstructor
而用@Builder
试试呢,但是compile就报错了:无法将类 com.bones.pojo.Emp中的构造器 Emp应用到给定类型;
请注意:我这时候加的是三个注解:
报错到底是为什么呢?
@Builder
注解默认用的是全参数构造函数,此时会导致无法new无参对象,为了解决这个问题往往会在@Builder
注解的类上加上@NoArgsConstructor
注解或者手动加上无参构造函数,此时虽然可以new无参对象了,但却会报上面这个错误。原因就是在类上贴了@NoArgsConstructor注解,此时只会生成无参构造器。
解决:解决方法很简单,只需在使用
@Builder
注解的类上再加上@AllArgsConstructor
注解即可.此时重新编译,不仅没有报错,而且查看字节码文件,发现还多了一个内部静态类
image-20221015130325095 3.关于查询,也可以设置模糊查询,以ename(员工姓名)字段为例:
非模糊查询:
<if test="ename != null and ename != ''">
and ename = #{ename}
</if>
模糊查询:(比如查询名称中带有"A")
<if test="ename != null and ename != ''">
and ename like concat('%',#{ename},'%')
</if>测试:
@Test
public void testFindByCondition(){
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = new Emp(null, "LL", null, null, null, null, null, null);
List<Emp> empList = empMapper.findByCondition(emp);
empList.forEach(System.out::println);
}查询结果:
image-20221015163535789 4.
where 1=1
这个技巧所带来的好处,后面的每一个if标签都需要带上and 再加条件就可以了。否则对于语句 的拼接将比较麻烦。5.在测试方法中,什么参数都不传的情况之下,将查询所有数据:
Emp emp = new Emp();
List<Emp> empList = empMapper.findByCondition(emp);此时通过打印的日志可以看到查询的语句是
DEBUG - ==> Preparing: select * from emp where 1=1
where标签
在所有的if标签之外套上where标签,并且sql语句不需要再写
where 1=1
select * from emp
<where>
<if test="empno != null">
and empno = #{empno}
</if>
.......
.......
.......
<if test="deptno != null">
and deptno = #{deptno}
</if>
</where>where
标签解决的就是where 1=1
的问题,在没有查询条件的时候,就不再拼接where语句了,在有多个查询的语句的时候,会拼接上,同时会解决多余或者缺少的and。image-20221015165209226 image-20221015165301874 when标签和choose标签
和
where
标签搭配使用接口
EmpMapper
:List<Emp> findByCondition2(Emp emp);
Mapper映射文件:
<select id="findByCondition2" resultType="emp">
select * from emp
<where>
<choose>
<when test="empno != null">
and empno = #{empno}
</when>
<when test="ename != null and ename != ''">
and ename like concat('%',#{ename},'%')
</when>
<when test="job != null and job != ''">
and ename = #{ename}
</when>
<when test="mgr != null">
and mgr = #{mgr}
</when>
<when test="hiredate != null">
and hiredate = #{hiredate}
</when>
<when test="sal != null">
and sal = #{sal}
</when>
<when test="comm != null">
and comm = #{comm}
</when>
<when test="deptno != null">
and deptno = #{deptno}
</when>
</choose>
</where>
</select>和
if
不同的是:if是多个条件都会查,而choose-when标签只会根据顺序查询一个。比如:
@Test
public void testFindByCondition2(){
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = new Emp();
emp.setEname("A");
emp.setDeptno(30);
List<Emp> empList = empMapper.findByCondition2(emp);
empList.forEach(System.out::println);
}现在查询名字中包含A,部门号是30的员工,日志中打印的SQL语句是:
DEBUG - ==> Preparing: select * from emp WHERE ename like concat('%',?,'%')
也就是说,choose标签中的when只要满足一个就不再往下判断了,写的越前面,查询的优先级越高。
实际到底用if多还是choose-when用的多?看实际需求。
set标签
前面的几个标签是针对于数据库 的查询,下面介绍更改。
现在接口中的抽象方法是:
int updateByCondition(Emp emp);
完成的功能是根据传入的emp对象,按照员工编号
empno
更改相关数据,如果传入的是null就说明不需要修改这个字段。利用set标签完成更改数据:(因为是update标签,所以不需要写returnType和ParameterType)
Mapper映射文件内容:
<!-- int updateByCondition(Emp emp);-->
<update id="updateByCondition">
update emp
<set>
<if test="ename != null and ename != ''">
, ename = #{ename}
</if>
<if test="job != null">
, job = #{job}
</if>
<if test="mgr != null">
, mgr = #{mgr}
</if>
<if test="hiredate != null">
, hiredate = #{hiredate}
</if>
<if test="sal != null">
, sal = #{sal}
</if>
<if test="comm != null">
, comm = #{comm}
</if>
<if test="deptno != null">
, deptno = #{deptno}
</if>
</set>
where empno = #{empno}
</update>测试方法:
@Test
public void testUpdateByCondition(){
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = new Emp();
emp.setEmpno(7654);
emp.setDeptno(10);
empMapper.updateByCondition(emp);
//提交事务
sqlSession.commit();
}注意:
1.要提交事务,否则数据库不会显示更新的数据
2.一定要传参数empno,否则没法根据empno更改数据
3.要在每个条件之前加上逗号,否则报错。
trim标签
set
标签和where
标签可以看作是trim
标签的特例。将之前提到过的
set
标签和where
标签做相应的修改,改为trim
标签where
标签<select id="findByCondition" resultType="emp">
select * from emp
<where>
<if test="empno != null">
and empno = #{empno}
</if>
......
<if test="deptno != null">
and deptno = #{deptno}
</if>
</where>
</select>改为
trim
标签:<select id="findByCondition3" resultType="emp">
select * from emp
<trim prefix="where" prefixOverrides="and">
<if test="empno != null">
and empno = #{empno}
</if>
......
<if test="deptno != null">
and deptno = #{deptno}
</if>
</trim>
</select>
set
标签<update id="updateByCondition">
update emp
<set>
<if test="ename != null and ename != ''">
, ename = #{ename}
</if>
......
<if test="deptno != null">
, deptno = #{deptno}
</if>
</set>
where empno = #{empno}
</update>改为
trim
标签<update id="updateByCondition2" >
update emp
<trim prefix="set" prefixOverrides=",">
<if test="ename != null and ename != ''">
, ename = #{ename}
</if>
<if test="job != null">
, job = #{job}
</if>
<if test="mgr != null">
, mgr = #{mgr}
</if>
<if test="hiredate != null">
, hiredate = #{hiredate}
</if>
<if test="sal != null">
, sal = #{sal}
</if>
<if test="comm != null">
, comm = #{comm}
</if>
<if test="deptno != null">
, deptno = #{deptno}
</if>
</trim>
where empno = #{empno}
</update>trim 标签有几个属性:
prefix:要添加的前缀
prefixOverrides:添加前缀之后,需要动态修改的内容(比如加上set之后,就要求参数之间用
,
连接,但是第一个参数跟在set之后,又不需要,
连接)suffix:要添加的前缀
suffixOverrides:添加后缀之后,需要动态修改的内容(与
prefixOverrides
类似)bind标签
这个标签和模糊查询有关。
首先回顾在mybatis中,不用
bind
标签如何书写模糊查询:<if test="ename != null and ename != ''">
and ename like concat('%',#{ename},'%')
</if>用的是concat 进行参数的拼接。
现在改为用
bind
标签进行处理:<if test="ename != null and ename != ''">
<bind name="enamePattern" value="'%'+ename+'%'"/>
and ename like #{enamePattern}
</if>bind
一般用于处理模糊查询的模板.sql标签
在写纯的sql语句的时候时常会碰到相同的部分,比如对于emp表进行操作:
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where ename like ....
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno = ... and ...
insert into emp (empno,ename,job,mgr,hiredate,sal,comm,deptno) values(......)
发现其实有很多内容是反复使用的。
那么可不可以因此“偷个懒”呢?在mybatis中答案当然是可以的!
下面以之前几个案例,利用sql标签来完善(改善)一下
EmpMapper.xml
文件首先将需要反复利用的部分抽成sql标签中的内容:
<sql id="empColumn">empno,ename,job,mgr,hiredate,sal,comm,deptno</sql>
<sql id="empBaseSelect">select <include refid="empColumn"/> from emp</sql>在上面的例子中已经看出了,如何使用sql中反复出现的标签内容,那就是用include标签。而且在sql标签中可以嵌套include标签。然后修改EmpMapper.xml中的sql查询语句:
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bones.mapper.EmpMapper">
<sql id="empColumn">empno,ename,job,mgr,hiredate,sal,comm,deptno</sql>
<sql id="empBaseSelect">select <include refid="empColumn"/> from emp</sql>
<!-- List<Emp> findByCondition(Emp emp);-->
<select id="findByCondition" resultType="emp">
<include refid="empBaseSelect"/>
<where>
<if test="empno != null">
and empno = #{empno}
</if>
.....
</where>
</select>
<!-- List<Emp> findByCondition2(Emp emp);-->
<select id="findByCondition2" resultType="emp">
<include refid="empBaseSelect"/>
<where>
<choose>
<when test="empno != null">
and empno = #{empno}
</when>
......
</choose>
</where>
</select>
<!-- List<Emp> findByCondition3(Emp emp);-->
<select id="findByCondition3" resultType="emp">
<include refid="empBaseSelect"/>
<trim prefix="where" prefixOverrides="and">
<if test="empno != null">
and empno = #{empno}
</if>
......
</trim>
</select>
<!-- int updateByCondition(Emp emp);-->
<update id="updateByCondition">
update emp
<set>
<if test="ename != null and ename != ''">
, ename = #{ename}
</if>
......
</set>
where empno = #{empno}
</update>
<!-- int updateByCondition2(Emp emp);-->
<update id="updateByCondition2" >
update emp
<trim prefix="set" prefixOverrides=",">
<if test="ename != null and ename != ''">
, ename = #{ename}
</if>
......
</trim>
where empno = #{empno}
</update>
</mapper>实际应用中,这个标签十分有用,因为这个标签可以实现一处修改,处处有效:
在实际开发中会遇到许多相同的SQL,比如根据某个条件筛选,这个筛选很多地方都能用到,我们可以将其抽取出来成为一个公用的部分,这样修改也方便,一旦出现了错误,只需要改这一处便能处处生效了,此时就用到了
<sql>
这个标签了。当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用。为求
<select>
结构清晰也可将 sql 语句分解。foreach标签
这个标签类似于java语法中的增强for循环:
for (Emp emp1 : empList) {
}在sql中使用的场景是in语句的查询。
比如现在的数据库表emp:
image-20221015210712888 想要查询工资是2000,2975,950的人,但是下一次要查询工资是1500,1250的人,如果用sql语句来写可以是:
select * from emp where SAL in(2000,2975,950);
select * from emp where SAL in(1500,1250);
如果用动态SQL该如何完成呢?
首先可以用数组/List/Map/Set来装要查询的数据。
准备Mapper接口的抽象方法:
List<Emp> findBySal1(iDouble[] sals);
List<Emp> findBySal2(List<Double> sals);在映射文件中完善两个抽象方法:
<!-- List<Emp> findBySal1(int[] sals);-->
<select id="findBySal1" resultType="emp">
<include refid="empBaseSelect"/> where sal in
<foreach collection="array" separator="," open="(" close=")" item="sal">
#{sal}
</foreach>
</select>
<!-- List<Emp> findBySal2(List<Double> sals);-->
<select id="findBySal2" resultType="emp">
<include refid="empBaseSelect"/> where sal in
<foreach collection="list" separator="," open="(" close=")" item="sal">
#{sal}
</foreach>
</select>测试方法:
@Test
public void testFindBySals(){
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> empList = empMapper.findBySal1(new Double[]{2000.0,2975.0,950.0});
System.out.println("findBySals1-----array");
empList.forEach(System.out::println);
}
@Test
public void testFindBySals2(){
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
List<Double> list = new ArrayList<>();
Collections.addAll(list,1500.0,1250.0);
List<Emp> empList = empMapper.findBySal2(list);
System.out.println("findBySals1-----list");
empList.forEach(System.out::println);
}3.浅析动态SQL的执行原理
其执行原理为,使用 OGNL 的表达式,从 SQL 参数对象中计算表达式的值,根据表达式的值动态拼接 SQL ,以此来完成动态 SQL 的功能。
原文始发于微信公众号(小东方不败):mybatis-动态SQL
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/47430.html