一、动态SQL
背景:
- 使用JDBC或其他类似的框架,需要根据不同的条件拼接SQL语句,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。而利用动态SQL,可以彻底解决这些问题。
说明:
- 动态SQL是mybatis强大的特性之一,极大地简化了拼装SQL的操作
- mybatis采用功能强大的基于OGNL的表达式来简化操作。
动态SQL元素:
- if
- choose(when,otherwise)
- trim(where,set)
- foreach
二、OGNL
说明:
- OGNL(Object Graph Navigation Language)对象图导航语言,这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。
操作:
- 访问对象属性:person.name
- 调用方法:person.getName()
- 调用静态属性/方法:@java.lang.Math@PI @java.util.UUID@randomUUID()
- 调用构造方法:new com.csu.marden.Person('admin').name
- 运算符:+、-、*、\、%
- 逻辑运算符:in、not in、>、>=、<、<=、==、!=
注意:
- xml中特殊符号如<、>等这些都需要使用转义字符
三、if元素
示例:查询员工。要求:员工携带了哪个字段,查询条件就带上这个字段的值。
例如:若查询的员工信息只携带了id属性,则按照id进行查询。若查询的员工信息携带了id属性和lastName属性,则按照id和lastName属性进行查询。若查询的员工信息携带了id属性,lastName属性和email属性,则按照id,lastName和email属性进行查询。
第一步:在员工类对应的接口中定义查询方法
package com.csu.marden;
import java.util.List;
public interface EmployeeMapperDynamicSQL {
//查询员工。要求:携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
}
第二步:在员工接口对应的sql映射文件中,定义动态SQL语句。
<?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="com.csu.marden.EmployeeMapperDynamicSQL">
<select id="getEmpsByConditionIf" resultType="employee">
select * from tbl_employee where
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email=#{email}
</if>
<if test="gender==0 or gender==1">
and gender=#{gender}
</if>
</select>
</mapper>
第三步:编写测试类
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee employee = new Employee(6,"%e%","jerry@csu.edu.cn","1");
List<Employee> result=mapper3.getEmpsByConditionIf(employee);
System.out.println(result);
}finally{
openSession.close();
}
}
}
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee employee = new Employee(6,"%e%","jerry@csu.edu.cn",null);
List<Employee> result=mapper3.getEmpsByConditionIf(employee);
System.out.println(result);
}finally{
openSession.close();
}
}
}
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee employee = new Employee(6,"%e%",null,null);
List<Employee> result=mapper3.getEmpsByConditionIf(employee);
System.out.println(result);
}finally{
openSession.close();
}
}
}
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee employee = new Employee(6,null,null,null);
List<Employee> result=mapper3.getEmpsByConditionIf(employee);
System.out.println(result);
}finally{
openSession.close();
}
}
}
问题1:查询的时候,如果某些条件不完整,可能出现SQL拼装错误!
示例:
解决方案:
1. 给where后面加上1=1,以后的if条件都以and xxx的形式书写
2. mybatis使用where标签来将所有的查询条件包括在内,将拼装SQL时,可以多出的and或or去掉。(where标签只能解决SQL语句前面多出的and或or,不能解决SQL语句后面多出的and或or)
问题2:查询的时候,and或者or在拼接的SQL后面,仍然会出现SQL拼装错误!(where标签不能解决SQL语句后面多出的and或or)
示例:
四、trim元素
作用:
- 自定义字符串的截取规则
属性:
- prefix属性: 给trim标签体中拼串后的整个字符串加一个前缀
- prefixOverrides属性:(前缀覆盖)去掉整个字符串前面多余的字符
- suffix属性: 给trim标签体中拼串后的整个字符串加一个后缀
- suffixOverrides属性:(后缀覆盖)去掉整个字符串后面多余的字符
应用:
- trim元素与where元素结合(where元素封装查询条件)
- trim元素与set元素结合(set元素封装修改条件)
示例1:trim元素与where元素结合(封装查询条件)
第一步:在员工类接口中定义查询方法
package com.csu.marden;
import java.util.List;
public interface EmployeeMapperDynamicSQL {
//查询员工。要求:携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
//查询员工,自定义SQL字符串截取规则
public List<Employee> getEmpsByConditionTrim(Employee employee);
}
第二步:在接口类对应的sql映射文件中定义SQL语句,以及自定义字符串截取规则
<?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="com.csu.marden.EmployeeMapperDynamicSQL">
<!-- 测试if元素 -->
<select id="getEmpsByConditionIf" resultType="employee">
select * from tbl_employee
<where>
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email=#{email}
</if>
<if test="gender==0 or gender==1">
and gender=#{gender}
</if>
</where>
</select>
<!-- 测试trim元素 -->
<select id="getEmpsByConditionTrim" resultType="employee">
select * from tbl_employee
<!-- prefix属性: 给trim标签体中拼串后的整个字符串加一个前缀-->
<!-- prefixOverrides属性:(前缀覆盖)去掉整个字符串前面多余的字符 -->
<!-- suffix属性: 给trim标签体中拼串后的整个字符串加一个后缀 -->
<!-- suffixOverrides属性:(后缀覆盖)去掉整个字符串后面多余的字符 -->
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null && lastName!=""">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=""">
email=#{email} and
</if>
<if test="gender==0 or gender==1">
gender=#{gender}
</if>
</trim>
</select>
</mapper>
第三步:编写测试类
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee employee = new Employee(null,"%e%",null,null);
List<Employee> result=mapper3.getEmpsByConditionTrim(employee);
System.out.println(result);
}finally{
openSession.close();
}
}
}
示例2:trim元素与set元素结合(封装修改条件)
问题:直接拼接SQL语句,若有多余的逗号会造成SQL语句拼接错误!
解决方案1:使用set标签去除多余的逗号
解决方案2:使用trim标签和set元素结合
五、choose元素
作用:
- 从多个条件中选择一个条件使用,类似于Java中的switch语句
示例:查询员工,如果有id信息,则按照id查询;如果有last_name信息,则按照last_name查询。。。(只会选择其中一个条件查询)
第一步:在员工类接口中定义查询方法
package com.csu.marden;
import java.util.List;
public interface EmployeeMapperDynamicSQL {
//查询员工。要求:携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
//查询员工,自定义SQL字符串截取规则
public List<Employee> getEmpsByConditionTrim(Employee employee);
//查询员工,选择其中一个条件查询
public List<Employee> getEmpsByConditionChoose(Employee employee);
}
第二步:在接口对应的sql映射文件中,编写sql语句,以及choose条件选择
<?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="com.csu.marden.EmployeeMapperDynamicSQL">
<!-- 测试if元素 -->
<select id="getEmpsByConditionIf" resultType="employee">
select * from tbl_employee
<where>
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email=#{email}
</if>
<if test="gender==0 or gender==1">
and gender=#{gender}
</if>
</where>
</select>
<!-- 测试trim元素 -->
<select id="getEmpsByConditionTrim" resultType="employee">
select * from tbl_employee
<!-- prefix属性: 给trim标签体中拼串后的整个字符串加一个前缀-->
<!-- prefixOverrides属性:(前缀覆盖)去掉整个字符串前面多余的字符 -->
<!-- suffix属性: 给trim标签体中拼串后的整个字符串加一个后缀 -->
<!-- suffixOverrides属性:(后缀覆盖)去掉整个字符串后面多余的字符 -->
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null && lastName!=""">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=""">
email=#{email} and
</if>
<if test="gender==0 or gender==1">
gender=#{gender}
</if>
</trim>
</select>
<!-- 测试choose元素 -->
<select id="getEmpsByConditionChoose" resultType="employee">
select * from tbl_employee
<where>
<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>
gender=0
</otherwise>
</choose>
</where>
</select>
</mapper>
第三步:编写测试类
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee employee = new Employee(null,null,null,null);
List<Employee> result=mapper3.getEmpsByConditionChoose(employee);
System.out.println(result);
}finally{
openSession.close();
}
}
}
六、foreach元素
作用:
对集合进行遍历查询(尤其是在构建in条件语句的时候)。可以指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。允许指定开头(open)和结尾(close)的字符串,以及集合项迭代之间的分割符(separator)。
属性:
- collection属性:传入参数的集合类型!!!
- item属性:将当前遍历出的元素赋值给指定的变量
- separator属性:每个元素之间的分隔符
- open属性:遍历出的结果拼接一个开始的字符(遍历元素的语句以什么开始)
- close属性:遍历出的结果拼接一个结束的字符(遍历元素的语句以什么结束)
- index属性:遍历list的时候是索引,遍历map的时候是map的key
注意:(collection属性值)
- 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
- 如果传入的是单参数且参数类型是一个array数组的时候,collection属性值是array
- 如果传入的是多参数,我们可以手动把它们封装成Map,这个时候collection属性值是map的key
第一种情况:单参数List类型:
<select id="countByUserList" resultType="_int" parameterType="list">
select count(*) from users
<where>
id in
<foreach item="item" collection="list" separator="," open="(" close=")" index="">
#{item.id, jdbcType=NUMERIC}
</foreach>
</where>
</select>
public void shouldHandleComplexNullItem() {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
Mapper mapper = sqlSession.getMapper(Mapper.class);
User user1 = new User();
user1.setId(2);
user1.setName("User2");
List<User> users = new ArrayList<User>();
users.add(user1);
users.add(null);
int count = mapper.countByUserList(users);
Assert.assertEquals(1, count);
} finally {
sqlSession.close();
}
}
第二种情况:单参数array类型:
<select id="dynamicForeach2Test" resultType="Blog">
select * from t_blog where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
public void dynamicForeach2Test() {
SqlSession session = Util.getSqlSessionFactory().openSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
int[] ids = new int[] {1,3,6,9};
List blogs = blogMapper.dynamicForeach2Test(ids);
for (Blog blog : blogs)
System.out.println(blog);
session.close();
}
第三种情况:多参数时手动封装map类型:
<select id="dynamicForeach3Test" resultType="Blog">
select * from t_blog where title like "%"#{title}"%" and id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
public void dynamicForeach3Test() {
SqlSession session = Util.getSqlSessionFactory().openSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
final List ids = new ArrayList();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(6);
ids.add(7);
ids.add(9);
Map params = new HashMap();
params.put("ids", ids);
params.put("title", "中国");
List blogs = blogMapper.dynamicForeach3Test(params);
for (Blog blog : blogs)
System.out.println(blog);
session.close();
}
示例1:查询的输入是集合类型
第一步:在接口类中定义查询方法
package com.csu.marden;
import java.util.List;
public interface EmployeeMapperDynamicSQL {
//查询员工。要求:携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
//查询员工,自定义SQL字符串截取规则
public List<Employee> getEmpsByConditionTrim(Employee employee);
//查询员工,选择其中一个条件查询
public List<Employee> getEmpsByConditionChoose(Employee employee);
//更新员工信息,根据传入的员工对象,有什么属性更新什么属性
public void updateEmp(Employee employee);
//根据传入的List集合,查询对应的员工信息
public List<Employee> getEmpsByConditionForeach(List<Integer> ids);
}
第二步:在接口类对应的sql映射文件中定义集合的查询方法
<?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="com.csu.marden.EmployeeMapperDynamicSQL">
<!-- 测试if元素 -->
<select id="getEmpsByConditionIf" resultType="employee">
select * from tbl_employee
<where>
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email=#{email}
</if>
<if test="gender==0 or gender==1">
and gender=#{gender}
</if>
</where>
</select>
<!-- 测试trim元素 ,与where元素结合-->
<select id="getEmpsByConditionTrim" resultType="employee">
select * from tbl_employee
<!-- prefix属性: 给trim标签体中拼串后的整个字符串加一个前缀-->
<!-- prefixOverrides属性:(前缀覆盖)去掉整个字符串前面多余的字符 -->
<!-- suffix属性: 给trim标签体中拼串后的整个字符串加一个后缀 -->
<!-- suffixOverrides属性:(后缀覆盖)去掉整个字符串后面多余的字符 -->
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null && lastName!=""">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=""">
email=#{email} and
</if>
<if test="gender==0 or gender==1">
gender=#{gender}
</if>
</trim>
</select>
<!-- 测试trim元素 ,与set元素结合-->
<update id="updateEmp">
update tbl_employee
<!-- 拼接的SQL语句使用prefix增加前缀,使用suffixOverrides去除后面多余的逗号 -->
<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>
<!-- 测试choose元素 -->
<select id="getEmpsByConditionChoose" resultType="employee">
select * from tbl_employee
<where>
<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>
gender=0
</otherwise>
</choose>
</where>
</select>
<!-- 测试foreach元素-->
<!-- collection元素:指定要遍历的集合,list类型的参数会特殊处理封装在map中,map的key就叫list -->
<!-- item元素:将当前遍历出的元素赋值给指定的变量 -->
<!-- separator元素:每个元素之间的分隔符 -->
<!-- open元素:遍历出所有结果拼接一个开始的字符 -->
<!-- close元素:遍历出所有结果拼接一个结束的字符 -->
<!-- index元素:遍历list的时候是索引,遍历map的时候是map的key -->
<select id="getEmpsByConditionForeach" resultType="employee">
select * from tbl_employee where id in
<foreach collection="list" item="item_id" separator="," open="(" close=")">
#{item_id}
</foreach>
</select>
</mapper>
第三步:编写测试类
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
List<Integer> ids=new ArrayList<Integer>();
ids.add(1);
ids.add(5);
ids.add(6);
List<Employee> result=mapper3.getEmpsByConditionForeach(ids);
System.out.println(result);
openSession.commit();
}finally{
openSession.close();
}
}
}
示例2:插入的参数是集合类型
第一步:在员工类接口中定义插入方法
package com.csu.marden;
import java.util.List;
public interface EmployeeMapperDynamicSQL {
//查询员工。要求:携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
//查询员工,自定义SQL字符串截取规则
public List<Employee> getEmpsByConditionTrim(Employee employee);
//查询员工,选择其中一个条件查询
public List<Employee> getEmpsByConditionChoose(Employee employee);
//更新员工信息,根据传入的员工对象,有什么属性更新什么属性
public void updateEmp(Employee employee);
//根据传入的List集合,查询对应的员工信息
public List<Employee> getEmpsByConditionForeach(List<Integer> ids);
//批量插入
public void addEmps(List<Employee> emps);
}
第二步:在接口类对应的sql映射文件中编写插入的sql语句
<!-- 测试foreach元素-->
<insert id="addEmps">
insert into tbl_employee (last_name,gender,email,d_id)
values
<foreach collection="list" item="item_emp" separator=",">
(#{item_emp.lastName},#{item_emp.gender},#{item_emp.email},#{item_emp.dept.id})
</foreach>
</insert>
第三步:编写测试类
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
List<Employee> result=new ArrayList<Employee>();
result.add(new Employee(null, "smith", "smith@csu.edu.cn", "1",new Department(1)));
result.add(new Employee(null, "allen", "allen@csu.edu.cn", "0",new Department(2)));
result.add(new Employee(null, "mike", "mike@csu.edu.cn", "1",new Department(1)));
mapper3.addEmps(result);
openSession.commit();
}finally{
openSession.close();
}
}
}
补充:mybatis的两个内置参数
- _parameter参数:代表整个参数。如果是单个参数,_parameter就是这个参数;如果是多个参数,这些参数会被封装为一个map,_parameter就是代表这个map
- _databaseId参数:_databaseId代表当前数据库的别名,需要配置databaseIdProvider标签。
七、bind元素
说明:
可以使用bind标签将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值。
示例:
第一步:在接口类中定义查询方法
package com.csu.marden;
import java.util.List;
public interface EmployeeMapperDynamicSQL {
//查询员工。要求:携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
//查询员工,自定义SQL字符串截取规则
public List<Employee> getEmpsByConditionTrim(Employee employee);
//查询员工,选择其中一个条件查询
public List<Employee> getEmpsByConditionChoose(Employee employee);
//更新员工信息,根据传入的员工对象,有什么属性更新什么属性
public void updateEmp(Employee employee);
//根据传入的List集合,查询对应的员工信息
public List<Employee> getEmpsByConditionForeach(List<Integer> ids);
//批量插入
public void addEmps(List<Employee> emps);
//模糊查询,使用bind标签绑定
public List<Employee> getEmpsByConditionBind(Employee employee);
}
第二步:在接口对应的sql映射文件中编写查询方法,并使用bind标签绑定
<!-- 测试bind标签 -->
<select id="getEmpsByConditionBind" resultType="employee">
<bind name="lastName" value="'%'+_parameter.lastName+'%'"/>
select * from tbl_employee where last_name like #{lastName}
</select>
第三步:编写测试类
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee employee = new Employee(null,"en",null,null);
List<Employee> result=mapper3.getEmpsByConditionBind(employee);
System.out.println(result);
openSession.commit();
}finally{
openSession.close();
}
}
}
八、sql元素
作用:
抽取可重用的sql片段,方便后面引用
使用:
- 使用sql标签将可常用的sql片段抽取
- 使用include标签引用已抽取的sql片段
示例:
第一步:在接口类中定义查询方法
package com.csu.marden;
import java.util.List;
public interface EmployeeMapperDynamicSQL {
//查询员工。要求:携带了哪个字段查询条件就带上这个字段的值
public List<Employee> getEmpsByConditionIf(Employee employee);
//查询员工,自定义SQL字符串截取规则
public List<Employee> getEmpsByConditionTrim(Employee employee);
//查询员工,选择其中一个条件查询
public List<Employee> getEmpsByConditionChoose(Employee employee);
//更新员工信息,根据传入的员工对象,有什么属性更新什么属性
public void updateEmp(Employee employee);
//根据传入的List集合,查询对应的员工信息
public List<Employee> getEmpsByConditionForeach(List<Integer> ids);
//批量插入
public void addEmps(List<Employee> emps);
//模糊查询,使用bind标签绑定
public List<Employee> getEmpsByConditionBind(Employee employee);
//根据id查询员工信息,使用sql标签抽取可重用部分
public Employee getEmpByConditionSQL(Integer id);
}
第二步:在接口对应的sql映射文件中定义sql查询语句,使用sql标签抽取可重用部分
<!-- 测试sql标签 -->
<sql id="selectColumn">
id,last_name,gender,email
</sql>
<select id="getEmpByConditionSQL" resultType="employee">
select
<include refid="selectColumn"></include>
from tbl_employee
where id=#{id}
</select>
第三步:编写测试类
package com.csu.marden;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
//1.根据xml配置文件(全局配置文件,即mybatis-config.xml)创建一个SqlSessionFactory对象
String resources="mybatis-config.xml";
InputStream inputStream=Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//2.根据SqlSessionFactory创建SqlSession,每个SqlSession代表和数据库的一次会话
SqlSession openSession=sqlSessionFactory.openSession();
try{
//3.获取接口的实现类对象(mybatis会为接口自动创建一个代理对象,代理对象会执行增删改查)
EmployeeMapperPlus mapper1=openSession.getMapper(EmployeeMapperPlus.class);
DepartmentMapper mapper2=openSession.getMapper(DepartmentMapper.class);
EmployeeMapperDynamicSQL mapper3=openSession.getMapper(EmployeeMapperDynamicSQL.class);
//4.通过接口的实现类对象调用接口的查询方法
Employee result=mapper3.getEmpByConditionSQL(1);
System.out.println(result);
openSession.commit();
}finally{
openSession.close();
}
}
}