MyBatis 的强大特性之一便是它的动态 SQL,本章介绍动态 SQL
查看本章,请先阅读【Mybatis】MyBatis对表执行CRUD操作(三)。
本例表结构
1 CREATE TABLE `employee` ( 2 `id` int(11) NOT NULL AUTO_INCREMENT, 3 `last_name` varchar(255) DEFAULT NULL, 4 `gender` char(1) DEFAULT NULL, 5 `email` varchar(255) DEFAULT NULL 6 PRIMARY KEY (`id`) 7 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
if
if标签:用于逻辑判断,其中test属性,填写的是判断表达式(OGNL)
示例
1、EmployeeMapper新增Sql如下:
1 <!-- if:判断 --> 2 <select id="testConditionIf" 3 resultType="com.hd.test.pojo.Employee"> 4 select id, last_name lastName, gender from employee 5 <!-- 6 test:判断表达式(OGNL) OGNL参照PPT或者官方文档。 7 c:if test 从参数中取值进行判断 遇见特殊符号应该去写转义字符: &&: 8 9 --> 10 where 1 = 1 11 <if test="id != null"> 12 AND id = #{id} 13 </if> 14 <!-- 表达式中,字符串使用''单引号引起来 --> 15 <if test="lastName != null and lastName.trim() != ''"> 16 AND last_name = #{lastName} 17 </if> 18 <!-- ognl会进行字符串与数字的转换判断 "0"==0 --> 19 <if test="gender==0 or gender==1"> 20 AND gender = #{gender} 21 </if> 22 <!-- 转义字符: && == && "" == ""--> 23 <if test="email != null && lastName!="""> 24 AND email = #{email} 25 </if> 26 </select>
2、EmployeeMapper接口中,新增方法
1 public List<Employee> testConditionIf(Employee employee);
3、测试方法
1 @Test 2 public void test001() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sessionFactory.openSession(); 8 9 try { 10 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); 11 List<Employee> list = mapper.testConditionIf(new Employee(null, "0", null)); 12 System.out.println(list.size()); 13 for (Employee employee : list) { 14 System.out.println(list); 15 } 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } finally { 19 session.close(); 20 } 21 }
4、执行结果
choose
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
示例
1、EmployeeMapper新增Sql如下:
1 <!-- choose --> 2 <select id="testConditionChoose" resultType="com.hd.test.pojo.Employee"> 3 select id, last_name lastName, gender from employee 4 where 1 = 1 5 <choose> 6 <when test="id != null"> 7 AND id = #{id} 8 </when> 9 <when test="lastName != null"> 10 AND last_name = #{lastName} 11 </when> 12 <when test="gender != null"> 13 AND gender = #{gender} 14 </when> 15 <when test="email != null"> 16 AND email = #{email} 17 </when> 18 <otherwise> 19 AND 1 = 1 20 </otherwise> 21 </choose> 22 </select>
2、EmployeeMapper接口中,新增方法
1 public List<Employee> testConditionChoose(Employee employee);
3、测试方法
1 @Test 2 public void test002() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sessionFactory.openSession(); 8 9 try { 10 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); 11 List<Employee> list = mapper.testConditionChoose(new Employee(1, null, null, null)); 12 System.out.println(list.size()); 13 for (Employee employee : list) { 14 System.out.println(list); 15 } 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } finally { 19 session.close(); 20 } 21 }
4、执行结果
where
where标签:用于编写带where条件的sql,配合if标签使用,它会自动去除首个AND前缀。
示例
1、EmployeeMapper新增Sql如下:
1 <!-- if + where --> 2 <select id="testConditionIfWhere" 3 resultType="com.hd.test.pojo.Employee"> 4 select id, last_name lastName, gender from employee 5 <where> 6 <if test="id != null"> 7 AND id = #{id} 8 </if> 9 <if test="lastName != null and lastName.trim() != ''"> 10 AND last_name = #{lastName} 11 </if> 12 <if test="gender==0 or gender==1"> 13 AND gender = #{gender} 14 </if> 15 <if test="email != null && lastName!="""> 16 AND email = #{email} 17 </if> 18 </where> 19 </select>
2、EmployeeMapper接口中,新增方法
1 public List<Employee> testConditionIfWhere(Employee employee);
3、测试方法
1 @Test 2 public void test003() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sessionFactory.openSession(); 8 9 try { 10 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); 11 List<Employee> list = mapper.testConditionIfWhere(new Employee("小红", "1", null)); 12 System.out.println(list.size()); 13 for (Employee employee : list) { 14 System.out.println(list); 15 } 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } finally { 19 session.close(); 20 } 21 }
4、执行结果
trim
trim标签:可以去掉字符串的首尾字符串,以及在字符串前后添加前后缀
示例
1、EmployeeMapper新增Sql如下:
1 <select id="testConditionIfTrim" resultType="com.hd.test.pojo.Employee"> 2 select id, last_name lastName, gender from employee 3 <!-- 后面多出的and或者or where标签不能解决 4 prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。 prefix给拼串后的整个字符串加一个前缀 5 prefixOverrides="": 前缀覆盖: 去掉整个字符串前面多余的字符 6 suffix="":后缀 suffix给拼串后的整个字符串加一个后缀 7 suffixOverrides="" 后缀覆盖:去掉整个字符串后面多余的字符 --> 8 <trim prefix="where" prefixOverrides="AND"> 9 <if test="id != null"> 10 AND id = #{id} 11 </if> 12 <if test="lastName != null"> 13 AND last_name = #{lastName} 14 </if> 15 <if test="gender != null"> 16 AND gender = #{gender} 17 </if> 18 <if test="email != null"> 19 AND email = #{email} 20 </if> 21 </trim> 22 </select>
2、EmployeeMapper接口中,新增方法
1 public List<Employee> testConditionIfTrim(Employee employee);
3、测试方法
1 @Test 2 public void test004() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sessionFactory.openSession(); 8 9 try { 10 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); 11 List<Employee> list = mapper.testConditionIfTrim(new Employee(1, null, null, null)); 12 System.out.println(list.size()); 13 for (Employee employee : list) { 14 System.out.println(list); 15 } 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } finally { 19 session.close(); 20 } 21 }
4、执行结果
foreach
动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候
示例
1、EmployeeMapper新增Sql如下:
1 <!-- foreach --> 2 <select id="testConditionForeach" resultType="com.hd.test.pojo.Employee"> 3 select id, last_name lastName, gender from employee 4 <!-- 5 collection:指定要遍历的集合: 6 list类型的参数会特殊处理封装在map中,map的key就叫list 7 item:将当前遍历出的元素赋值给指定的变量 8 separator:每个元素之间的分隔符 9 open:遍历出所有结果拼接一个开始的字符 10 close:遍历出所有结果拼接一个结束的字符 11 index:索引。遍历list的时候是index就是索引,item就是当前值 12 遍历map的时候index表示的就是map的key,item就是map的值 13 14 #{变量名}就能取出变量的值也就是当前遍历出的元素 15 --> 16 <foreach collection="ids" item="id" separator="," open="where id in (" close=")" > 17 #{id} 18 </foreach> 19 </select>
2、EmployeeMapper接口中,新增方法
1 public List<Employee> testConditionForeach(@Param("ids")List<Integer> ids);
3、测试方法
1 @Test 2 public void test005() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sessionFactory.openSession(); 8 9 try { 10 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); 11 List<Employee> list = mapper.testConditionForeach(Arrays.asList(1, 2, 3, 4)); 12 System.out.println(list.size()); 13 for (Employee employee : list) { 14 System.out.println(list); 15 } 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } finally { 19 session.close(); 20 } 21 }
4、执行结果
set
set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号
示例
1、EmployeeMapper新增Sql如下:
1 <!-- set --> 2 <update id="testConditionSet"> 3 update employee 4 <set> 5 <if test="lastName != null"> 6 last_name = #{lastName}, 7 </if> 8 <if test="gender != null"> 9 gender = #{gender}, 10 </if> 11 <if test="email != null"> 12 email = #{email}, 13 </if> 14 </set> 15 where id = #{id} 16 </update>
2、EmployeeMapper接口中,新增方法
1 public boolean testConditionSet(Employee employee);
3、测试方法
1 @Test 2 public void test006() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sessionFactory.openSession(); 8 9 try { 10 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); 11 boolean f = mapper.testConditionSet(new Employee(1, "小白", "1", null)); 12 System.out.println(f); 13 session.commit(); 14 } catch (Exception e) { 15 e.printStackTrace(); 16 } finally { 17 session.close(); 18 } 19 }
4、执行结果
bind
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:
1 <select id="testConditionBind" resultType="Blog"> 2 <bind name="pattern" value="'%' + keyword + '%'" /> 3 SELECT * FROM employee WHERE last_name LIKE #{pattern} 4 </select>
sql
可以用来包含其他sql
1 <sql id="selectSql">select id, last_name lastName, gender from employee</sql> 2 3 <select id="testConditionInclude" resultType="com.hd.test.pojo.Employee"> 4 <include refid="selectSql"></include> 5 where id = 1 6 </select>
Mybatis中2个内置参数 _parameter和_databaseId
示例
1、EmployeeMapper新增Sql如下:
1 <!-- 两个内置参数: 2 不只是方法传递过来的参数可以被用来判断,取值。。。 3 mybatis默认还有两个内置参数: 4 _parameter:代表整个参数 5 单个参数:_parameter就是这个参数 6 多个参数:参数会被封装为一个map;_parameter就是代表这个map 7 8 _databaseId: 9 如果配置了databaseIdProvider标签。 _databaseId就是代表当前数据库的别名mysql 10 如果没配置了databaseIdProvider标签。 _databaseId为null 11 --> 12 <select id="testInnerParameter" resultType="com.hd.test.pojo.Employee"> 13 <if test="_databaseId == 'mysql'">select * from ${_parameter}</if> 14 <if test="_databaseId != 'mysql'">select * from ${_parameter} where 1 = 1</if> 15 </select>
2、mybatis-config.xml中的配置
1 <databaseIdProvider type="DB_VENDOR"> 2 <!-- 为不同的数据库厂商起别名 --> 3 <property name="MySQL" value="mysql"/> 4 <property name="Oracle" value="oracle"/> 5 <property name="SQL Server" value="sqlserver"/> 6 </databaseIdProvider>
3、EmployeeMapper接口中,新增方法
1 public List<Employee> testInnerParameter(String tableName);
4、测试方法
1 @Test 2 public void test007() throws IOException { 3 4 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 5 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 6 7 SqlSession session = sessionFactory.openSession(); 8 9 try { 10 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class); 11 List<Employee> list = mapper.testInnerParameter("employee"); 12 System.out.println(list.size()); 13 for (Employee employee : list) { 14 System.out.println(employee); 15 } 16 17 } catch (Exception e) { 18 e.printStackTrace(); 19 } finally { 20 session.close(); 21 } 22 }
5、执行结果,从执行结果可以看出,_parameter == employee 参数,_databaseId == mysql 数据库别名