Mybatis框架(5) —— 动态SQL语句

动态SQL语句

动态SQL是什么?

就是相对与固定SQL。就是通过传入的参数不一样,可以组成不同结构的SQL语句。这种根据参数的条件修改SQL结构的SQL语句,我们称之为动态SQL语句

动态SQL有什么用?

1.根据条件组装不同结构的SQL语句,可以提高SQL代码的重用性
2.满足某些特定需求,如,条件判断查询

基于XML的实现

标签包括

<sql>用于声明公有的SQL语句块,在操作标签中使用<include>调用
<if>类似java if(){},用于判断
<foreach>:类似Java的foreach循环,一般用户批量处理的SQL语句
<trim>:切割标签,主要用于切割关键字的头和尾的字符,新版的Mybatis使用的几率很少
<set>:使用set标签就是SQL语言的set关键字,可以在update的时候set关键字后面的,逗号可以自动省略
<where>:使用where标签作为SQL语言的where关键字,好处如果where后面的条件都不成立,忽略where关键字
<choose><when><otherwise>:Java的switch case

接口文件

package cn.xc.mybatis.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import cn.xc.mybatis.pojo.User;

public interface UserMapper {

	/**
	 * 根据条件查询结果
	 * @param user
	 * @return
	 */
	List<User> selectByCondition(User user);
	
	/**
	 * 根据提交查询总数
	 * @param user
	 * @return
	 */
	Long selectTotalByConditin(User user);
	
	/**
	 * 修改用户
	 * @param user
	 * @return
	 */
	int updateUserByNotNull(User user);
	
	/**
	 * 批量删除用户
	 * @param ids 
	 * (@Param("ids")Integer[] ids)==> 相当与Map 的 key + 参数 + 实参
	 * @return
	 */
	int deleteByIds(@Param("ids")Integer[] ids);
	
	/**
	 * 批量插入
	 * Batch (分批处理)
	 * @param users
	 * @return
	 */
	int insertByBatch(@Param("users")List<User> users);
}

映射文件

<?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=""> 映射的根元素 namespace属性:命名空间 (唯一),必须是当前对应映射接口的全限定名 
	全限定名 : 包名+简单类名/接口名 cn.xc.mybatis.mapper.UserMapper -->
<mapper namespace="cn.xc.mybatis.mapper.UserMapper">
	
	<!-- 多行查询 resultType : 只是返回的当行数据封装的对象类型,无论单行还是多行查询都必须返回对应的 实体类型User -->
	<select id="selectByCondition" parameterType="cn.xc.mybatis.pojo.User" resultType="cn.xc.mybatis.pojo.User">
		<!-- 错误写法 select * from user name like '%#{name}%' or age = #{age} -->
		<!-- 
			select * from user where name like concat('%',#{name},'%') or age = #{age}
			上述SQL语句的语义来说,是一个静态的SQL语句,一开始已经确定SQL的语义
			不管有没有数据,都会对全部数据进行修改,如果某一个数据没有,name会自动设置为null
			不符合实际场景
			
			解决方案:使用Mybatis的动态SQL语句
		 -->
		select * from user 
		<!-- 
			<include refid="condition_sql"/>
			包含引入sql片段
			refid :被引入的sql片段的id值
		 -->
		<include refid="condition_sql"/>
	</select>
	
	<!-- 
		<sql id=""></sql>
		抽取sql片段
		id属性:片段的唯一标识,以供其他地方使用
	 -->
	<!-- <sql id="condition_sql">
		动态SQL语句
			<where>标签
			 	在where内部编写条件
			 	1.如果只要满足一个条件<where>标签会自动拼接 WHERE 关键字拼接上对应的条件
			 	2.如果条件前面有 OR|AND 关键字,但是是第一个条件,那么会自动删除这个关键字,以保证语法正确
			 	3.如果一个条件都没有,那么就相当于查询所有的数据
		
		 <where>
		 	<if test="name != null">
		 		name like concat('%',#{name},'%')
		 	</if>
		 	<if test="age != null">
		 		or age = #{age}
		 	</if>
		 </where>
	</sql> -->
	
	<sql id="condition_sql">
		<!-- 
			<trim>标签,开发者可以自定义条件,既可以指定where条件也可以指定set关键字条件
			<trim prefix="where" prefixOverrides="AND|OR">
			prefix :前缀,
				当前如果是 	条件就用 where
				如果使用修改 	就用		set
			prefixOverrides :如果在where关键字后面第一个条件,如果是AND|OR会自动去掉
		 -->
		<trim prefix="where" prefixOverrides="AND|OR">
			<if test="name != null">
				name like concat('%',#{name},'%')
			</if>
			<if test="age != null">
				or age = #{age}
			</if>
		</trim>
	</sql>
	
	<select id="selectTotalByCondition" parameterType="cn.xc.mybatis.pojo.User" resultType="long">
		select count(*) from user
		<!-- 
			<include refid="condition_sql"/>
			包含引入sql片段
			refid :被引入的sql片段的id值
		 -->
		<include refid="condition_sql"></include>
	</select>
	
	<!-- 修改操作 -->
	<update id="updateUserByNotNull" parameterType="cn.xc.mybatis.pojo.User">
		
		<!-- 
			update user set name = #{name},password = #{password},age = #{age} where id = #{id}
			上述SQL语句的语义来说,是一个静态的SQL语句,一开始已经确定SQL的语义
			不管有没有数据,都会对全部数据进行修改,如果某一个数据没有,name会自动设置为null
			不符合实际场景
			解决方案:使用MyBatis的动态SQL语句
		 -->
		 
		 <!-- 
	  	 	动态sql语句 <set>标签  
	  	  	<trim prefix="WHERE" prefixOverrides="AND | OR">
	  	  -->
	  	  
	  	  update user
	  	  <!-- <set>
	  	  	<if test="name != null">
	  	  		name = #{name},
	  	  	</if>
	  	  	<if test="password != null">
	  	  		password = #{password},
	  	  	</if>
	  	  	<if test="age != null">
	  	  		age = #{age}
	  	  	</if>
	  	  </set> -->
	  	  
	  	  <!-- 
  	  		prefix : 前缀,
  	 		当前如果是 条件就用  WERHE
  	 		如果使用修改 就用  SET
  	 		prefixOverrides :如果在 WHRE 关子健 后面的第一个条件,如果是 AND|OR 会自动去掉
  	 		suffixOverrides :如果是最后一个条件, 如果是多余的逗号(,) 会自动去掉
	  	  -->
	  	  <trim prefix="set" suffixOverrides=",">
	  	  	<if test="name !=null">name = #{name},</if>
	  	  	<if test="password !=null">password = #{password},</if>
	  	  	<if test="age !=null">age = #{age}</if>
	  	  </trim>
	  	  where id = #{id}
	</update>
	
	<!-- 批量删除 -->
	<delete id="deleteByIds" parameterType="list">
		<!-- delete from user where id in (1,2,3) -->
	
		<!-- 
			<foreach collection="" open="" close="" item="" separator="">标签体内容</foreach> 
			MyBatis的for循环标签
			collection:循环集合
			open:起始括号(
			close:结束括号 )
			item:集合每次循环的数据对应的变量
			separator:分割符号: (1,2,3) 数值与数值之间的分隔符 ,逗号
		-->
		delete from user where id in
		<foreach collection="ids" open="(" close=")" item="id" separator=",">
			#{id}
		</foreach>
	</delete>
	
	<insert id="insertByBatch">
		<!-- insert into user (name,password,age)values -->
		insert into user (name,password,age)values
		<foreach collection="users" item="user" separator=",">
			(#{user.name},#{user.password},#{user.age})
		</foreach>
	</insert>
</mapper>

测试代码

package cn.xc.mybatis.test;

import java.util.Arrays;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import cn.xc.mybatis.mapper.UserMapper;
import cn.xc.mybatis.pojo.User;
import cn.xc.mybatis.utils.MyBatisUtil;

public class UserMapperTest {
	
	// 多行查询
	@Test
	public void testSelectByCondition() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);
		
		//条件对象
		User conditionUser = new User();
		conditionUser.setName("哥");
		//conditionUser.setAge(30);
		
		// 3. 执行多行查询方法
		List<User> users = userMapper.selectByCondition(conditionUser);
		Long total = userMapper.selectTotalByCondition(conditionUser);
		
		for (User user : users) {
			System.out.println(user);
		}
		
		System.out.println(total);
		session.close();
	}
	
	// 修改功能
	@Test
	public void testUpdateUserByNotNull() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);

		// 3.执行update方法
		User user = new User();
		user.setId(7);
		user.setName("杰克");
		user.setPassword("xjg");

		int row = userMapper.updateUserByNotNull(user);
		
		// 4.手动提交事务
		session.commit();
		// 5.关闭Session
		session.close();
	}
	
	
	// 批量删除
	@Test
	public void testDeleteByBatch() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);

		Integer[] ids = {1,2,3,4};
		
		int row = userMapper.deleteByIds(ids);
		
		// 4.手动提交事务
		//session.commit();
		// 5.关闭Session
		session.close();
	}
	
	// 批量插入
	@Test
	public void testInsertByBatch() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);

		User u1 = new User(null,"TOM","tom",50);
		User u2 = new User(null,"Jerry","jerry",50);
		List<User> users = Arrays.asList(u1,u2);
		
		int row = userMapper.insertByBatch(users);
		
		// 4.手动提交事务
		session.commit();
		// 5.关闭Session
		session.close();
	}
}

基于注解方式实现

动态sql除了支持xml方式以外,还是支持使用纯注解的方式
主要一下四个注解+对应动态sql语句的类文件
1.@SelectProvider 动态查询SQL语句对应注解
2.@InsertProvider 动态插入SQL语句对应注解
3.@UpdateProvider 动态修改SQL语句对应注解
4.@DeleteProvider 动态删除SQL语句对应注解

接口映射文件

package cn.xc.mybatis.mapper;

import java.util.List;

import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;

import cn.xc.mybatis.pojo.User;
import cn.xc.mybatis.pojo.UserSQLProvider;

public interface UserMapper {
	
	/**
	 * @SelectProvider(type = UserSQLProvider.class,method = "selectByCondition")
	 * 查询动态sql语句的注解
	 * type :拼接动态sql语句的类的字节码
	 * method :UserSqlProvider 类中返回动态查询sql语句的方法名
	 * 注意:USerSQLProvider中对应的方法的参数必须和UserMapper中对应的方法参数一样
	 * 		方法名理论上可以不限,但是建议一般和UserMapper接口中的方法名一致,(阅读更直观清晰)
	 */
	@SelectProvider(type = UserSQLProvider.class,method = "selectByCondition")
	List<User> selectByCondition(User user);
	
	/**
	 * 根据提交查询总数
	 * @param user
	 * @return
	 */
	@SelectProvider(type = UserSQLProvider.class,method = "selectTotalByCondition")
	Long selectTotalByCondition(User user);
	
	/**
	 * 修改用户
	 * @param user
	 * @return
	 */
	@UpdateProvider(type = UserSQLProvider.class,method="updateUserByNotNull")
	int updateUserByNotNull(User user);
	
	/**
	 * 批量删除用户
	 * @param ids 
	 * (@Param("ids")Integer[] ids)==> 相当与Map 的 key + 参数 + 实参
	 * @return
	 */
	@DeleteProvider(type = UserSQLProvider.class,method="deleteByIds")
	int deleteByIds(@Param("ids")Integer[] ids);
	
	/**
	 * 批量插入
	 * Batch (分批处理)
	 * @param users
	 * @return
	 */
	@InsertProvider(type = UpdateProvider.class,method="insertByBatch")
	int insertByBatch(@Param("users")List<User> users);
}

动态sql语句文件

(在查询上有些bug)
UserSQLProvider.java

package cn.xc.mybatis.pojo;

import java.util.List;

import org.apache.ibatis.annotations.Param;

//拼接动态sql语句的类
public class UserSQLProvider {
	/*
	 * 返回查询的动态SQL语句
	 */
	public String selectByCondition(User user) {
		StringBuilder sb = new StringBuilder();
		sb.append("select * from user where ");
		// 注意:返回动态SQl语句不是纯粹的SQL字符串,直接的拼接一定是 使用OGMNL 表达式
		if (user.getName() != null) {
			sb.append("name like concat('%',#{name},'%')");
		}
		if (user.getAge() != null) {
			sb.append("or age = #{age}");
		}
		return sb.toString();
	}

	public String selectTotalByCondition(User user) {
		StringBuilder sb = new StringBuilder();
		sb.append("select count(*) from user where ");
		// 注意:返回动态SQl语句不是纯粹的SQL字符串,直接的拼接一定是 使用OGMNL 表达式
		if (user.getName() != null) {
			sb.append("name like concat('%',#{name},'%')");
		}
		if (user.getAge() != null) {
			sb.append("or age = #{age}");
		}
		return sb.toString();
	}

	public String updateUserByNotNull(User user) {
		StringBuilder sb = new StringBuilder();
		sb.append("update user set ");
		if (user.getName() != null) {
			sb.append("name = #{name},");
		}
		if (user.getPassword() != null) {
			sb.append("password = #{password},");
		}
		if (user.getAge() != null) {
			sb.append("age = #{age},");
		}
		// 删除最后一个多余的逗号
		sb.deleteCharAt(sb.length() - 1);
		sb.append(" where id = #{id}");

		return sb.toString();
	}
	
	// 批量删除
	public String deleteByIds(@Param("ids") Integer[] ids) {
		StringBuilder sb = new StringBuilder();
		/*
		 * delete from user where id in (#{ids[0],#{ids[1]}})
		 */
		sb.append("delete from user where id in (");
		for (int i = 0; i < ids.length; i++) {
			sb.append("#{ids["+i+"]},");
		}
		// 删除最后一个多余的逗号
		sb.deleteCharAt(sb.length() - 1);
		sb.append(")");
		System.out.println("sql:"+sb.toString());
		return sb.toString();
	}
	
	// 批量插入
	public String insertByBatch(@Param("users") List<User> users) {
		StringBuilder sb = new StringBuilder();
		/*
		 * insert into user (name,password,age)values 
			('露SEI','lusei',18),('丽丽','lili',20)
			
			insert into user (name,password,age)values 
			(#{users[0].name},#{users[0].password},#{users[0].age }),(#users[1].name,#users[1].password,#{users[1].age })
		 */
		sb.append("insert into user (name,password,age)values ");
		for (int i = 0; i < users.size(); i++) {
			sb.append("(");
			sb.append("#{users["+i+"].name},");
			sb.append("#{users["+i+"].password},");
			sb.append("#{users["+i+"].age}");
			sb.append("),");
		}
		// 删除最后一个多余的逗号
		sb.deleteCharAt(sb.length() - 1);
		System.out.println("sql:"+sb.toString());
		return sb.toString();
	}
}

测试代码

package cn.xc.mybatis.test;

import java.util.Arrays;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import cn.xc.mybatis.mapper.UserMapper;
import cn.xc.mybatis.pojo.User;
import cn.xc.mybatis.utils.MyBatisUtil;

public class UserMapperTest {
	
	// 多行查询
	@Test
	public void testSelectByCondition() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);
		
		//条件对象
		User conditionUser = new User();
		conditionUser.setName("哥");
		//conditionUser.setAge(30);
		
		// 3. 执行多行查询方法
		List<User> users = userMapper.selectByCondition(conditionUser);
		Long total = userMapper.selectTotalByCondition(conditionUser);
		
		for (User user : users) {
			System.out.println(user);
		}
		
		System.out.println(total);
		session.close();
	}
	
	// 修改功能
	@Test
	public void testUpdateUserByNotNull() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);

		// 3.执行update方法
		User user = new User();
		user.setId(7);
		user.setName("杰克");
		user.setPassword("xjg");

		int row = userMapper.updateUserByNotNull(user);
		
		// 4.手动提交事务
		session.commit();
		// 5.关闭Session
		session.close();
	}
	
	
	// 批量删除
	@Test
	public void testDeleteByBatch() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);

		Integer[] ids = {1,2,3,4};
		
		int row = userMapper.deleteByIds(ids);
		
		// 4.手动提交事务
		//session.commit();
		// 5.关闭Session
		session.close();
	}
	
	// 批量插入
	@Test
	public void testInsertByBatch() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper 映射接口的代理对象(接口不能直接创建对象,底层创建代理对象)
		UserMapper userMapper = session.getMapper(UserMapper.class);

		User u1 = new User(null,"TOM","tom",50);
		User u2 = new User(null,"Jerry","jerry",50);
		List<User> users = Arrays.asList(u1,u2);
		
		int row = userMapper.insertByBatch(users);
		
		// 4.手动提交事务
		session.commit();
		// 5.关闭Session
		session.close();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值