四大标签
if
choose(when,other)
trim(where,set):where封装查询条件,set封装修改条件,都是和if结合使用
foreach
下面来一一介绍并测试,测试内容是基于上一篇的JavaBean和数据库Mybatis----resultMap详解及应用(一)
一、if标签
结合where标签:
需求:查询员工:携带了哪个字段,查询条件就带上这个字段的值。
mapper接口中的方法和对应的映射规则:
public List<Employee> getEmpsByConditionIf(Employee e);
<select id="getEmpsByConditionIf" resultType="bean.Employee">
select * from tbl_employee
<!-- where 1=1 -->
<where>
<!-- OGNL表达式:从参数中取值进行判断-->
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null and lastName!=''">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=''">
and email=#{email}
</if>
<!--ognl会进行字符串和数字的转换 "0"==0是可以的-->
<if test="gender==0 or gender==1">
and gender=#{gender};
</if>
</where>
</select>
在未使用 < where >标签之前,会出现一些sql拼装的问题,例如查询条件中id为空,sql语句where后面直接跟着一个and显然是不合理的。解决办法如下:
方法一:where关键字后面拼上1=1,之后所有情况的sql语句都会带上...where 1=1 and...
方法二:mybatis使用where标签来将所有的查询条件包括在内.mybatis自动将where标签中拼装的
sql多出来的and或者or去掉,只会去掉第一个,推荐将所有的and或or写在句首
结合set标签:实现添加员工方法
需求: 修改员工:携带了哪个字段,修改条件就带上这个字段的值。
mapper接口中的方法和对应的映射规则:
public void updateEmp(Employee e);
<update id="updateEmp">
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标签
prefix: 前缀:在整个拼接的动态sql语句前加上前缀
prefixOverride: 前缀覆盖:去掉整个字符串前面多余的字符
suffix: 后缀:给拼串后额整个字符串加一个后缀
suffixOverride: 后缀覆盖:去掉后面多余的字符
方法声明和映射规则:
public List<Employee> getEmpsByConditionTrim(Employee e);
<select id="getEmpsByConditionTrim" resultType="bean.Employee">
select * from tbl_employee
<!--自定义字符串截取规则-->
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null and lastName!=''">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=''">
email=#{email} and
</if>
<!--ognl会进行字符串和数字的转换 "0"==0是可以的-->
<if test="gender==0 or gender==1">
gender=#{gender} and;
</if>
</trim>
</select>
使用trim标签实现上面的新增员工方法:
set关键字放在prefix中,逗号放在suffixOverride中,如果后续没有条件,多余的逗号将被剪掉
<update id="updateEmp">
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>
</update>
三、choose标签
它的作用类似于switch-case
方法声明和映射规则:
public List<Employee> getEmpsByConditionChos(Employee e);
<select id="getEmpsByConditionChos" resultType="bean.Employee">
select * from tbl_employee
<where>
<!-- 如果带了id就用id查,如果带了lastName就用lastName查;都没有则查询全部
只会进入其中一个分支-->
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="lastName!=null">
last_name like #{lastName}
</when>
<when test="email!=null">
email=#{email}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
四、foreach标签
foreach标签中的属性:
collection:指定要遍历的集合的key:
list类型的参数会特殊处理封装在map中,map的key就叫list
item:每次遍历出的元素起一个变量名,方便引用,使用 #{} 取值
index:索引
如果遍历的是一个list:
index,指定的变量保存了当前索引
item,就是保存当前遍历元素的值
如果遍历的是一个map:
index,指定的变量就是保存了当前遍历元素的key
item,就是保存当前遍历元素的值
close:以什么结束
open:以什么开始
separator:每次遍历元素的分隔符
需求一:查询员工ID集合里面包含的所有相关员工信息
方法声明和映射规则:
public List<Employee> getEmpsByConditionForeach(@Param("ids") List<Integer> list);
可以使用@param()注解给参数命名。
<select id="getEmpsByConditionForeach" resultType="bean.Employee">
select * from tbl_employee where id in
<foreach collection="ids" item="item_id" separator="," open="(" close=")">
#{item_id}
</foreach>
</select>
需求二:批量保存:
方法声明和映射规则:
public void addEmps(@Param("emps") List<Employee> emps);
方法一:MySQL支持…values(),(),()的方式批量插入
<insert id="addEmps">
insert into tbl_employee(last_name,email,gender,d_id)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
</insert>
方法二:使用foreach直接插入完整的sql语句、
需要注意的是要开启MySQL的多句查询,在dbconfig.properties中的jdbc.url 后面加入
?allowMultiQueries=ture
,同时要求数据库引擎支持,可将MySQL的引擎切换到InnoDB。
<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>
五、动态SQL四大标签测试
package MybatisTest;
import bean.Department;
import bean.Employee;
import dao.EmployeeMapperDynamicSQL;
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.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MybatisTest {
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "config\\mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test1() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
Employee employee = new Employee(null,"%o%",null,null);
//测试if标签
List<Employee> empsByConditionIf = mapper.getEmpsByConditionIf(employee);
for (Employee employee1 :empsByConditionIf) {
System.out.println(employee1);
}
/*查询的时候如果某些条件没带可能会导致sql拼装有问题
方法一:where关键字后面拼上1=1,之后所有情况的sql语句都会带上...where 1=1 and...
方法二:mybatis使用where标签来将所有的查询条件包括在内.mybatis自动将where标签中拼装的
sql多出来的and或者or去掉,只会去掉第一个,推荐将所有的and或or写在句首
*/
//测试trim标签
List<Employee> empsByConditionTrim = mapper.getEmpsByConditionTrim(employee);
for (Employee employee1 :empsByConditionTrim) {
System.out.println(employee1);
}
//测试choose(when,otherwise)
List<Employee> empsByConditionChos = mapper.getEmpsByConditionChos(employee);
System.out.println(empsByConditionChos);
//测试set标签
//直接使用set关键字会导致逗号问题,使用set或trim标签解决
Employee employee1 = new Employee(1, null, "112233@qq.com", null);
mapper.updateEmp(employee1);
openSession.commit();
//测试foreach标签
List<Employee> empsByConditionForeach = mapper.getEmpsByConditionForeach(Arrays.asList(1, 4, 5));
for (Employee e :empsByConditionForeach) {
System.out.println(e);
}
}finally {
openSession.close();
}
}
//测试批量添加
@Test
public void test2() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
List<Employee> emps=new ArrayList<>();
emps.add(new Employee(null,"timmy","987456@163.com","1",new Department(1)));
emps.add(new Employee(null,"allen","555666@163.com","0",new Department(2)));
mapper.addEmps(emps);
openSession.commit();
}finally {
openSession.close();
}
}
}
六、两个内置参数和sql标签
还剩一点点内容,就记在一起吧。
方法传递过来的参数不只可以被用来判断,取值。。。
mybatis默认还有两个内置参数:
_parameter:代表传过来的整个参数
单个参数:_parameter就是这个参数
多个参数:参数会被封装为一个map
_databaseId:如果配置了DatabaseIdProvider标签。
_databaseId就是代表当前数据库的别名
查两种数据库
以前的方法每个select 后面带一个databaseId
现在通过if标签结合_databaseId :全局配置文件中配置了databaseIdProvider之后
bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值
public List<Employee> getEmpsTestInnerParameter(Employee e);
<select id="getEmpsTestInnerParameter" resultType="bean.Employee">
<bind name="_lastName" value="'%'+lastName+'%'"/>
<if test="_databaseId==mysql">
select * from tbl_employee
<if test="_parameter!=null">
where last_name=#{_lastName}
</if>
</if>
<if test="_databaseId==oracle">
select * from employees
<if test="_parameter!=null">
where last_name=#{_parameter.lastName}
</if>
</if>
</select>
测试:一般不会这样做模糊查询,将%直接放在参数中比较灵活,而不用修改xml文件
@Test
public void testInnerParam() throws IOException{
sqlsessionFactory sqlSessionFactory = getsqisessionFactory();
sqlsession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapperDynamicsQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
Employee employee2 = newEmployee();
employee2.setLastName("e");
List<Employee> list = mapper.getEmpsTestInnerParameter(employee2)
for (Employee employee : list){
system.out.println(employee);
}
}
}
七、sql标签–与增删改同级的标签
抽取共同的sql片段,一般抽取要查询的列名或者插入的列名。
insert into tbl_employee values(
<include refid="insertColumn">
<property name="testColumn" value="abc"
</include>
)
<sql id="insertColumn">
<if test="_databaseId==mysql">
employee_id,last_name,email,${testColumn}
</if>
<if test="databaseId==oracle">
last_name,gender,email,d_id
</if>
</sql>
include标签内部还可以自定义一些property,sql标签内还能引用,用$取值 ${testColumn}
上面的testColumn是错误的,数据库中并没有这一列,仅作为演示。这样发送的sql语句还能看到insert …values(…,abc)