目录
一: 动态SQL
有的业务场景,也需要SQL语句进⾏动态拼接,例如:
①批量删除
delete from t_car where id in(1,2,3,4,5,6,....这⾥的值是动态的,根据⽤户选择的id不同,值是不同的);
②多条件查询
select * from t_car where brand like '丰⽥%' and guide_price > 30 and .....;
需求:多条件查询
可能的条件包括:品牌(brand)、指导价格(guide_price)、汽⻋类型(car_type)等
1. if标签
三兄弟之一:CarMapper接口,编写方法
参数有多个,使用@Param注解进行变量的定义,增强可读性!
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 多条件查询,使用if
List<Car> selectByMultiCondition(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
}
三兄弟之二:CarMapper.xml文件,编写sql语句
使用if标签,当条件满足就会把SQL语句拼接上去:
①if标签中test属性是必须的,test属性一般是一个表达式,对应的值是true或者false。
②test属性可以使用的是:
第一:当使用了@Param注解,test中要出现的必须是@Param注解指定的参数名;
第二:当没有使用@Param注解,test中出现的是:arg0、arg1或者param1、param2….
第三:当使用了POJO,test中出现的是POJO类的属性;
③在MyBatis的动态SQL当中,如果多个条件同时满足,不能使用&&,只能使用and。
<?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.bjpowernode.mybatis.mapper.CarMapper">
<select id="selectByMultiCondition" resultType="Car">
select * from t_car where
<if test="brand != null and brand != ''">
brand like "%"#{brand}"%"
</if>
<if test="guidePrice != null and guidePrice !=''">
and guide_price > #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</select>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
①假设三个参数都不为空,查询的结果完全没问题!
②假设三个参数都为空,就会出现问题,原来的SQL语句就变成:select * from t_car where,这是不符合语法的!怎么办?在where后面加上一个恒成立的条件 1=1
③假设第一个条件不为空,后两个两条都为空,那就是把第一条SQL语句直接拼上去,也会出现问题: select * from t_car where 1==1 brand like “%”?”%”,两个条件中间需要一个and作为连接,所以第一条语句前面也要加上and
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testSelectByMultiCondition(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 假设三个条件都不为空
List<Car> cars = mapper.selectByMultiCondition("比亚迪",2.0,"新能源");
// 假设三个条件都为空
List<Car> cars = mapper.selectByMultiCondition("",null,"");
// 假设第一个不为空,后两个为空
List<Car> cars = mapper.selectByMultiCondition("比亚迪",null,"");
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
}
所以最终的SQL语句修改为:增加1=1 和 and条件
<?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.bjpowernode.mybatis.mapper.CarMapper">
<select id="selectByMultiCondition" resultType="Car">
select * from t_car where 1=1
<if test="brand != null and brand != ''">
and brand like "%"#{brand}"%"
</if>
<if test="guidePrice != null and guidePrice !=''">
and guide_price > #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</select>
</mapper>
2. where标签
where标签的作⽤:让where⼦句更加动态智能
①所有条件都为空时,where标签保证不会⽣成where⼦句。
②⾃动去除某些条件前⾯多余的and或or。
三兄弟之一:CarMapper接口,编写方法
整个方法的结构不变,就改了一下方法名
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 使用where标签,让where子句更加的智能
List<Car> selectByMultiConditionWithWhere(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
}
三兄弟之二:CarMapper.xml文件,编写sql语句
使用where标签专门处理where子句,所以我们就可以按照原来的思路进行SQL语句的编写
注:如果把and写在语句后面,不能去除掉,只能去除掉前面多余的and,例如:brand like “%”#{brand}”%” and
<?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.bjpowernode.mybatis.mapper.CarMapper">
<select id="selectByMultiConditionWithWhere" resultType="Car">
select * from t_car
<where>
<if test="brand != null and brand != ''">
brand like "%"#{brand}"%"
</if>
<if test="guidePrice != null and guidePrice !=''">
and guide_price > #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</where>
</select>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
①假设三个都为空,where标签就不会生成where子句;
②假设第一个为空,后面两个都不为空,那么第二个带and的子句就会拼接上去,where标签会自动剔除掉多余的and;
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testSelectByMultiConditionWithWhere(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 三个都为空
List<Car> cars = mapper.selectByMultiCondition("",null,"");
// 假设第一个为空,后两个不为空
List<Car> cars = mapper.selectByMultiCondition("",2.0,"新能源");
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
}
3. trim标签
trim标签的属性:
①prefix:在trim标签中的语句前添加内容(加前缀)
②suffix:在trim标签中的语句后添加内容 (加后缀)
③prefixOverrides:前缀覆盖掉(去掉前缀)
④suffixOverrides:后缀覆盖掉(去掉后缀)
三兄弟之一:CarMapper接口,编写方法
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 使用trim标签
List<Car> selectByMultiConditionWithTrim(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
}
三兄弟之二:CarMapper.xml文件,编写sql语句
不使用where标签,使用prefix和suffixOverrides属性来完成查询操作,并且我们把and放到后面,也同样能完成操作,例如:
①prefix=”where”,表示在trim标签所有内容的前面添加where
②suffixOverrides=”and|or”,表示把trim标签中内容的后缀and或or去掉
<?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.bjpowernode.mybatis.mapper.CarMapper">
<select id="selectByMultiConditionWithTrim" resultType="Car">
select * from t_car
<trim prefix="where" suffixOverrides="and|or">
<if test="brand != null and brand != ''">
brand like "%"#{brand}"%" and
</if>
<if test="guidePrice != null and guidePrice !=''">
guide_price > #{guidePrice} and
</if>
<if test="carType != null and carType != ''">
car_type = #{carType}
</if>
</trim>
</select>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
①三个都为空,也是完全没有问题的,前缀增加where也不是随便就加的,需要先判断子句有没有,有子句才会加where
②第一个不为空,其余都为空,这样where子句后缀就多了一个and,前面我们定义的是suffixOverrides=”and|or”,把trim标签中内容的后缀and或or去掉,也是完全没问题的
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testSelectByMultiConditionWithTrim(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 三个都不为空
List<Car> cars = mapper.selectByMultiConditionWithTrim("", null, "");
// 第一个不为空,其它都为空
List<Car> cars = mapper.selectByMultiConditionWithTrim("比亚迪", null, "");
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
}
4. set标签
主要使⽤在update语句当中,⽤来⽣成set关键字,同时去掉最后多余的“,”
⽐如:我们只更新提交的不为空的字段,如果提交的数据是空或者””,那么这个字段我们将不更新。
(1)测试使用最初的方式进行更新
三兄弟之一:CarMapper接口,编写方法
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 通过id进行更新
int updateById(Car car);
}
三兄弟之二:CarMapper.xml文件,编写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.bjpowernode.mybatis.mapper.CarMapper">
<update id="updateById">
update t_car set
car_num = #{carNum},
brand = #{brand},
guide_price = #{guidePrice},
produce_time = #{produceTime},
car_type = #{carType}
where
id = #{id}
</update>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testUpdateById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = new Car(1L, null, null, null, null, "新能源");
int count = mapper.updateById(car);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
}
问题:原来已经存在的数据,但是我们更新时并没有传数据进去,它会把原来已经存的数据更新为空!
(2)使用set标签进行更新
三兄弟之一:CarMapper接口,编写方法
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 通过set标签进行更新
int updateBySet(Car car);
}
三兄弟之二:CarMapper.xml文件,编写sql语句
这里的set标签实际上有两个功能:
①完成数据的更新,对于没有赋值的字段不会更新,只更新提交数据不为空的字段
②删除多余的逗号,比如:最后一个字段car_type为空,这样就会多余一个逗号出来,set标签可以去除掉这个多余的逗号
<?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.bjpowernode.mybatis.mapper.CarMapper">
<update id="updateBySet">
update t_car
<set>
<if test="carNum != null and carNum !=''">car_num = #{carNum},</if>
<if test="brand != null and brand !=''">brand = #{brand},</if>
<if test="guidePrice != null and guidePrice !=''">guide_price = #{guidePrice},</if>
<if test="produceTime != null and produceTime !=''">produce_time = #{produceTime},</if>
<if test="carType != null and carType !=''">car_type = #{carType}</if>
</set>
where
id = #{id}
</update>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testUpdateBySet(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = new Car(2L, null, "奔驰C200", null, null, "新能源");
int count = mapper.updateBySet(car);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
}
更新结果如下,对于提交的数据是空或者””,这个字段将不会更新
5. choose when otherwise
这三个标签是在⼀起使⽤的,语法格式如下:
<choose>
<when></when>
<when></when>
<when></when>
<otherwise></otherwise>
</choose>
就等同于:
if(){
}else if(){
}else if(){
}else if(){
}else{
}
只有⼀个分⽀会被选择!
需求:先根据品牌查询,如果没有提供品牌,再根据指导价格查询,如果没有提供指导价格,就根据⽣产⽇期查询。
三兄弟之一:CarMapper接口,编写方法
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 根据chose when otherwise
List<Car> selectByChoose(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
}
三兄弟之二:CarMapper.xml文件,编写sql语句
三个条件:实际上是三选一,只要有其中一条执行了,其它分支就不会执行;所以都不需要加and
<?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.bjpowernode.mybatis.mapper.CarMapper">
<select id="selectByChoose" resultType="Car">
select * form t_car
<where>
<choose>
<when test="brand != null and brand !=''">
brand like "%"#{brand}"%"
</when>
<when test="guidePrice != null and guidePrice !=''">
guide_price > #{guidePrice}
</when>
<otherwise>
car_type = #{carType}
</otherwise>
</choose>
</where>
</select>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
①当三个条件都不为空,就按照第一个条件进行查询;当前面的条件为空,就依次按照后面的顺序进行查询
②特殊情况的三个条件都为空,实际上走的是最后otherwise标签的查询语句,只不过是把null传过去,查询不到数据而已
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testSelectByChoose(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 都不为空,按照第一个字段进行查询
List<Car> cars = mapper.selectByChoose("比亚迪", 2.0, "新能源");
// 都为空,按照最后一个字段进行查询,把null传过去
List<Car> cars = mapper.selectByChoose("", null, "");
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
}
6. foreach标签
循环数组或集合,动态⽣成sql,⽐如这样的SQL:
批量删除
delete from t_car where id in(1,2,3);
delete from t_car where id = 1 or id = 2 or id = 3;
批量添加
insert into t_car values
(null,'1001','凯美瑞',35.0,'2010-10-11','燃油⻋'),
(null,'1002','⽐亚迪唐',31.0,'2020-11-11','新能源'),
(null,'1003','⽐亚迪宋',32.0,'2020-10-11','新能源')
(1) 批量删除
三兄弟之一:CarMapper接口,编写方法
方法的参数是一个数组,这是第一次接触,重点掌握!
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 批量删除,foreach标签
int deleteByIds(@Param("ids") Long[] ids);
}
三兄弟之二:CarMapper.xml文件,编写sql语句
(1)foreach标签的属性:
①collection:指定数组或集合
②item:代表数组或集合中的元素,其实就是变量
③separater:循环之间的分隔符,肯定是逗号,因为SQL语句是这样的形式:delete from t_car where id in(1,2,3);
④open:foreach循环拼接的所有SQL语句的最前面以什么开始
⑤close:foreach循环拼接的所有SQL语句的最后面以什么结束
(2)collection参数怎么传一个数组或者集合?直接把ids拿过来?这样会报错,错误信息是:【array,arg0】说明底层创建了一个Map集合存储数据,例如:map.put(“array”,数组)或者map.put(“arg0”,数组);所以默认参数要使用array或者arg0;但是为了可读性,上面使用了@Param注解,就可以直接使用ids了
(3)第一、二种方法使用的是in的方式,分隔符用的是” 逗号, “;第三种方法使用or的方式,分隔符实际上就是or
<?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.bjpowernode.mybatis.mapper.CarMapper">
<delete id="deleteByIds">
<!--第一种方法-->
delete from t_car where id in(
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
)
<!--第二种方法-->
delete from t_car where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
<!--第三种方法:使用or的形式-->
delete from t_car where
<foreach collection="ids" item="id" separator="or">
id=#{id}
</foreach>
</delete>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
准备一个对应的数组传过去,数组中的数据是我们要删除元素对应的id
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testDeleteByIds(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 准备一个数组
Long[] ids = {1L,2L,4L};
int count = mapper.deleteByIds(ids);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
}
(2)批量插入
三兄弟之一:CarMapper接口,编写方法
批量插入:参数不在是一个数组,而是一个List集合,并且使用@Param注解起别名。
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface CarMapper {
// 批量插入,一次插入多条Car信息,foreach标签
int insertBatch(@Param("cars") List<Car> cars);
}
三兄弟之二:CarMapper.xml文件,编写sql语句
①这里最主要的就是如何传参?我们使用的是集合里面的元素Car,所以参数就是Car对应的属性名,直接“点”就可以了。
②同样这里集合中的元素也是通过逗号的形式作为分隔符,所以separator的参数也是” , “
<?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.bjpowernode.mybatis.mapper.CarMapper">
<insert id="insertBatch">
insert into t_car values
<foreach collection="cars" item="car" separator=",">
(null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
</foreach>
</insert>
</mapper>
三兄弟之三:CarMappeTest类,用来编写测试类
准备Car对象的数据,然后把这些Car对象的数据添加到List集合当中,最后把这个List集合当做参数传到方法当中
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testInsertBatch(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 准备数据
Car car1 = new Car(null,"1200", "帕萨特1", 30.0, "2020-11-11", "燃油车");
Car car2 = new Car(null,"1201", "帕萨特2", 30.0, "2020-11-11", "燃油车");
Car car3 = new Car(null,"1202", "帕萨特3", 30.0, "2020-11-11", "燃油车");
// 把数据添加到List集合当中
List<Car> cars = new ArrayList<>();
cars.add(car1);
cars.add(car2);
cars.add(car3);
// 把集合传过去
int count = mapper.insertBatch(cars);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
}
7. sql标签与include标签(了解)
(1)sql标签:⽤来声明sql⽚段,有id属性作为唯一标识。
(2)include标签:调用refid属性(传sql标签的id),将声明的sql⽚段包含到某个sql语句当中
作⽤:代码复⽤,易维护。
<!--重复的代码抽取出来-->
<sql id="carColumnNameSql">
id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
</sql>
<!--代码复用-->
<select id="selectAll" resultType="Car">
select
<include refid="carColumnNameSql"/>
from t_car;
</select>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/128405.html