动态SQL

动态SQL

开发人员在使用JDBC或其他类似的框架进行数据库开发时,通常都要根据需求去手动拼装SQL,这是一个非常麻烦且痛苦的工作,而MyBatis提供了对SQL语句动态组装的功能,恰好解决了这一麻烦工作。

动态SQL中的元素

动态SQL是MyBatis的强大特性之一,MyBatis 3采用了强大的基于OGNL的表达式来完成动态SQL,它消除了之前版本中需要了解的大多数元素,使用不到原来一半的元素就能完成所需工作。

元素说明
<if>判断语句,用于单条件分支判断
<choose>(<when><otherwise>)相当于Java中的swith…case…default语句,用于多条件分支判断
<where><trim><set>辅助元素,用于处理一些SQL拼接、特殊字符问题
<foreach>循环语句,常用于in语句等列举条件中
<bind>从OGNL表达式中创建一个变量,并将其绑定到上下文,常用于模糊查询的sql中

<if>元素

1)在Eclipse中,创建一个名为chapter08的Web项目,编写工具类MybatisUtils

package com.ex.utils;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.*;
public class MybatisUtils {
	private static SqlSessionFactory sqlSessionFactory=null;
	static{
		try{
			Reader reader=Resources.getResourceAsReader("mybatis-config.xml");
			sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	public static SqlSession getSession(){
		return sqlSessionFactory.openSession();
	}
}

2)编写映射关系

	 <select id="findCustomerByNameAndJobs"
	 	parameterType="com.ex.po.Customer"
	 	resultType="com.ex.po.Customer">
	 		select * from t_customer where 1=1
	 		<if test="username !=null and username!=''">
	 			and username like concat('%',#{username},'%')
	 		</if>
	 		<if test="jobs !=null and jobs !=''">
	 			and jobs=#{jobs}
	 		</if>
	 	</select>

使用if元素的test属性分别对username和jobs进行了非空判断,如果传入的查询条件不为空就进行动态SQL组装。
3)编写测试类

package com.ex.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import com.ex.po.*;
import com.ex.utils.*;
public class MybatisTest {
	@Test
	public void findCustomerByNameAndJobsTest(){
		SqlSession sqlSession=MybatisUtils.getSession();
		Customer customer=new Customer();
		customer.setUsername("jack");
		customer.setJobs("teacher");
		List<Customer> listCustomers=sqlSession.selectList("com.ex.mapper"
				+ "CustomerMapper.findCustomerByNameAndJobs", customer);
		for(Customer oneCustomer:listCustomers){
			System.out.println(oneCustomer);
		}
		sqlSession.close();
	}
}

在这里插入图片描述
传入一个空Customer对象
在这里插入图片描述
可以看到sql将数据库中所有的数据查出

<choose>、<when>、<otherwise>元素

1)在映射文件中,添加映射

	 	<select id="findCustomerByNameOrJobs"
	 		parameterType="com.ex.po.Customer"
	 		resultType="com.ex.po.Customer">
	 			select * from t_customer where 1=1
	 			<choose>
	 				<when test="username !=null and username !=''">
	 					and username like concat('%',#{username},'%')
	 				</when>
	 				<when test="jobs !=null and jobs !=''">
	 					and jobs=#{jobs}
	 				</when>
	 				<otherwise>
	 					and phone is not null
	 				</otherwise>
	 			</choose>
	 	</select>

注:choose只会选择一个分支,顺序判断分支条件,当满足条件时,就执行并跳出判断。(与switch…case…default有区别)
2)在测试类MybatisTest中,编写测试方法

	public void findCustomerByNameOrJobsTest(){
		SqlSession sqlSession=MybatisUtils.getSession();
		Customer customer=new Customer();
		customer.setUsername("jack");
		customer.setJobs("teacher");
		List<Customer> listCustomers=sqlSession.selectList("com.ex.mapper"
				+ ".CustomerMapper.findCustomerByNameOrJobs", customer);
		for(Customer oneCustomer:listCustomers){
			System.out.println(oneCustomer);
		}
		sqlSession.close();
	}

在这里插入图片描述
传入一个空对象
在这里插入图片描述

<where>、<trim>元素

在前面案例中,映射文件中编写的SQL后面都加入了"where 1=1"的条件,这是因为如果不添加会出现如下情况

select * from t_customer where and username like concat('%',?,'%')

where后直接跟and显然会报错,为了避免这一错误,我们添加1=1这一条件,能使拼接的sql成立。
针对这种问题,MyBatis提供了<where>元素来处理这些的问题。
例如上面的代码就可以写成

<select id="findCustomerByNameAndJobs"
	 	parameterType="com.ex.po.Customer"
	 	resultType="com.ex.po.Customer">
	 		select * from t_customer
	 		<where>
		 		<if test="username !=null and username!=''">
		 			and username like concat('%',#{username},'%')
		 		</if>
		 		<if test="jobs !=null and jobs !=''">
		 			and jobs=#{jobs}
		 		</if>
	 		</where>
	 	</select>

上述代码中使用<where>元素对where 1=1进行了替换,<where>元素会自动判断组合条件下拼接的SQL语句,只有<where>内的条件成立时,才会拼接SQL中加入where关键字,否则将不会添加;即使where之后的内容有多余的"AND"或"OR",<where>也会自动将它们取出。
除了使用<where>元素外,还可以通过<trim>元素来定制需要的功能

<select id="findCustomerByNameAndJobs"
	 	parameterType="com.ex.po.Customer"
	 	resultType="com.ex.po.Customer">
	 		select * from t_customer
	 		<trim prefix="where" prefixOverrides="and">
		 		<if test="username !=null and username!=''">
		 			and username like concat('%',#{username},'%')
		 		</if>
		 		<if test="jobs !=null and jobs !=''">
		 			and jobs=#{jobs}
		 		</if>
	 		</trim>
	 	</select>

<trim>元素对where 1=1条件进行了替换,<trim>元素的作用是去除一些特殊的字符串,它的prefix属性代表的是语句的前缀(这里使用where来连接sql),而prefixOverrides属性代表的是需要去除的特殊字符串(原sql的前缀),这里去除的是and,上面写法与<where>等效。

<set>元素

在Hibernate中,如果想要更新一个对象,就需要发送所有的字段给持久化对象,然而实际应用中,大多数情况都是更新某一个或某几个字段。如果更新的每一个数据都有将其所有的属性都更新一遍,那么其执行效率是非常差的。
MyBatis中提供了<set>元素来完成这一工作。元素用于更新操作,主要作用是在动态包含的SQL语句前输出一个SET关键字,并将SQL语句中最后一个多余的逗号去除。

	 	<update id="updateCustomer"
	 		parameterType="com.ex.po.Customer">
	 		update t_customer
	 		<set>
	 			<if test="username !=null and username !=''">
	 				username=#{username},
	 			</if>
	 			<if test="jobs !=null and jobs !=''">
	 				jobs=#{jobs},
	 			</if>
	 			<if test="phone !=null and phone !=''">
	 				phone=#{phone},
	 			</if>
	 		</set>
	 		where id=#{id}
	 	</update>
	@Test
	public void updateCustomer(){
		SqlSession sqlSession = MybatisUtils.getSession();
		Customer customer=new Customer();
		customer.setId(3);
		customer.setPhone("13314415515");
		int rows = sqlSession.update("com.ex.mapper"
				+ ".CustomerMapper.updateCustomer", customer);
		if(rows>0){
			System.out.println("你成功修改了"+rows+"条数据!");
		}else{
			System.out.println("执行修改操作失败!");
		}
		sqlSession.commit();
		sqlSession.close();
	}

在这里插入图片描述
在映射文件中使用<set><if>组合进行update语句动态SQL组装时,如果<set>元素内包含的内容都为空,则会出现SQL语法错误。所以在使用时需要注意。

<foreach>元素

Mybatis提供了一种用于数组和集合循环遍历的元素<foreach>
元素通常在构建IN条件语句时使用

	 	<select id="findCustomerByIds"
	 		parameterType="List"
	 		resultType="com.ex.po.Customer">
	 			select * from t_customer where id in
	 			<foreach item="id" index="index" collection="list"
	 				open="(" separator="," close=")">
	 					#{id}
	 			</foreach>
	 	</select>

item:配置的是循环中当前的元素
index:配置的是当前元素在集合的位置下标
collection:配置的list是传递过来的参数类型(首字母小写),它可以是一个array、list(或collection)、Map集合的键、POJO包装类中数组或集合类型的属性名等。
open和close:配置的是以什么符合将这些集合元素包装起来
separator:配置的是各个元素的间隔符
当使用可迭代对象或数组时,index是当前迭代的次数,item的值是本次迭代获取的元素。
当使用字典时,index是键,item是值。

	@Test
	public void findCustomerByIdsTest(){
		SqlSession sqlSession=MybatisUtils.getSession();
		List<Integer> ids=new ArrayList<Integer>();
		ids.add(1);
		ids.add(2);
		List<Customer> customers=sqlSession.selectList("com.ex.mapper"
				+ ".CustomerMapper.findCustomerByIds", ids);
		for(Customer customer:customers){
			System.out.println(customer);
		}
		sqlSession.close();
	}

在这里插入图片描述

<bind>元素

MyBatis的<bind>元素可以通过OGNL表达式来创建一个上下文变量

	 	<select id="findCustomerByName"
	 		parameterType="com.ex.po.Customer"
	 		resultType="com.ex.po.Customer">
	 			<bind name="pattern_username" value="'%'+_parameter.getUsername()+'%'"/>
	 			select * from t_customer
	 			where
	 			username like #{pattern_username}
	 	</select>
	@Test
	public void findCustomerByNameTest(){
		SqlSession sqlSession=MybatisUtils.getSession();
		Customer customer=new Customer();
		customer.setUsername("j");
		List<Customer> listCustomers=sqlSession.selectList("com.ex.mapper"
				+ ".CustomerMapper.findCustomerByName", customer);
		for(Customer oneCustomer:listCustomers){
			System.out.println(oneCustomer);
		}
		sqlSession.close();
	}

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值