MyBatis3框架详解(五)

一、动态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 &amp;&amp; lastName!=&quot;&quot;">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		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 &amp;&amp; lastName!=&quot;&quot;">
			 		and last_name like #{lastName}
			 	</if>
			 	<if test="email!=null and email.trim()!=&quot;&quot;">
			 		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 &amp;&amp; lastName!=&quot;&quot;">
			 		 last_name like #{lastName} and
			 	</if>
			 	<if test="email!=null and email.trim()!=&quot;&quot;">
			 		 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 &amp;&amp; lastName!=&quot;&quot;">
			 		and last_name like #{lastName}
			 	</if>
			 	<if test="email!=null and email.trim()!=&quot;&quot;">
			 		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 &amp;&amp; lastName!=&quot;&quot;">
			 		 last_name like #{lastName} and
			 	</if>
			 	<if test="email!=null and email.trim()!=&quot;&quot;">
			 		 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 &amp;&amp; lastName!=&quot;&quot;">
			 		and last_name like #{lastName}
			 	</if>
			 	<if test="email!=null and email.trim()!=&quot;&quot;">
			 		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 &amp;&amp; lastName!=&quot;&quot;">
			 		 last_name like #{lastName} and
			 	</if>
			 	<if test="email!=null and email.trim()!=&quot;&quot;">
			 		 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();
		}
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值