小黑子—MyBatis:第四章
MyBatis入门4.0
- 十 小黑子进行MyBatis参数处理
- 10.1 单个简单类型参数
- 10.1.1 单个参数Long类型
- 10.1.2 单个参数Date类型
- 10.2 Map参数
- 10.3 实体类参数(POJO参数)
- 10.4 多参数
- 10.5 @Param注解(命名参数)
- 10.6 @Param注解源码分析
- 十一 小黑子的MyBatis查询专题
- 11.1 返回Car
- 11.2 返回List< Car >
- 11.3 返回Map
- 11.3.1 返回List< Map >
- 11.4 返回Map<String.Map>
- 11.5 resultMap结果映射
- 11.5.1 开启驼峰命名自动映射
- 11.6返回总记录条数
- 十二 小黑子的动态SQL
- 12.1 if标签
- 12.2 where标签
- 12.3 trim标签
- 12.4 set标签
- 12.5 chose when otherwise标签
- 12.6 foreach标签
- 12.6.1 批量删除
- 12.6.2 批量插入
- 12.7 sql标签和include标签
十 小黑子进行MyBatis参数处理
10.1 单个简单类型参数
简单类型包括:
- byte short int long float double char
- Byte Short Integer Long Float Double Character
- String
- java.util.Date
- java.sql.Date
简单类型对于mybatis来说都是可以自动类型识别的:
- 也就是说对于mybatis来说,它是可以自动推断出ps.setXxxx()方法的。ps.setString()还是ps.setInt()。它可以自动推断。
其实SQL映射文件中的配置比较完整的写法是:
<select id="selectByName" resultType="student" parameterType="java.lang.String">select * from t_student where name = #{name, javaType=String, jdbcType=VARCHAR}
</select>
其中sql语句中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis进行类型确定的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。
- javaType:可以省略
- jdbcType:可以省略
- parameterType:可以省略
准备数据库:
目录展示:
10.1.1 单个参数Long类型
- StudentMapper
package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Student;import java.util.Date;
import java.util.List;public interface StudentMapper {/*** 当接口中的方法的参数只有一个(单给参数),并且参数的数据类型都是简单类型* 根据id查询、name查询、birth查询、sex查询* @version 1.0*/List<Student> selectById(Long id);List<Student> selectByName(String name);List<Student> selectByBirth(Date birth);List<Student> selectBySex(Character sex);
}
- StudentMappper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.StudentMapper">
<!--List<Student> selectById(int id);List<Student> selectByName(String name);List<Student> selectByBirth(String birth);List<Student> selectBySex(String sex);parameterType属性的作用:告诉mybatis框架,我这个方法的参数类型是什么类型mybatis框架自身带有类型自动推断机制,所以大部分情况下parameterType属性都是可以省略不写的SQL语句最终是这样的:select * from t_student where id = ?JDBC代码是一定要给?传值的,怎么传值?ps.setXxx(第几个问好,传什么值);ps.setLong(1,1L)ps.setString(1,"zhangsan")ps.setDate(1,new Date())ps.setInt(1,100)...mybatis底层到底调用setXxx的哪个方法,取决于parameterType属性的值
--><select id="selectById" resultType="Student" parameterType="java.lang.Long">select * from t_student where id = #{id}</select></mapper>
- 测试
package com.powernode.mybatis.test;import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.List;public class StudentMapperTest {@Testpublic void SelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> students = mapper.selectById(1L);students.forEach(student -> System.out.println(student));sqlSession.commit();sqlSession.close();}
}
10.1.2 单个参数Date类型
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.StudentMapper">
<!--List<Student> selectById(int id);List<Student> selectByName(String name);List<Student> selectByBirth(String birth);List<Student> selectBySex(String sex);parameterType属性的作用:告诉mybatis框架,我这个方法的参数类型是什么类型mybatis框架自身带有类型自动推断机制,所以大部分情况下parameterType属性都是可以省略不写的SQL语句最终是这样的:select * from t_student where id = ?JDBC代码是一定要给?传值的,怎么传值?ps.setXxx(第几个问好,传什么值);ps.setLong(1,1L)ps.setString(1,"zhangsan")ps.setDate(1,new Date())ps.setInt(1,100)...mybatis底层到底调用setXxx的哪个方法,取决于parameterType属性的值
--><select id="selectById" resultType="Student" parameterType="java.lang.Long">select * from t_student where id = #{id}</select><select id="selectByName" resultType="Student">select * from t_student where name = #{name,javaType=String,jdbcType=VARCHAR}</select><select id="selectByBirth" resultType="Student">select * from t_student where birth = #{birth}</select><select id="selectBySex" resultType="Student">select * from t_student where sex = #{sex}</select></mapper>
- 测试
package com.powernode.mybatis.test;import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;public class StudentMapperTest {@Testpublic void SelectBySex(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Character sex = Character.valueOf('男');List<Student> students = mapper.selectBySex(sex);students.forEach(student -> System.out.println(student));sqlSession.commit();sqlSession.close();}@Testpublic void SelectByBirth() throws ParseException {SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");Date birth = sdf.parse("1980-10-11");List<Student> students = mapper.selectByBirth(birth);students.forEach(student -> System.out.println(student));sqlSession.commit();sqlSession.close();}@Testpublic void SelectByName(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> students = mapper.selectByName("李四");students.forEach(student -> System.out.println(student));sqlSession.commit();sqlSession.close();}@Testpublic void SelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> students = mapper.selectById(1L);students.forEach(student -> System.out.println(student));sqlSession.commit();sqlSession.close();}
}
10.2 Map参数
这种方式是手动封装Map集合,将每个条件以key和value的形式存放到集合中。然后在使用的时候通过
#{map集合的key}
来取值
需求:根据map集合保存学生信息
- StudentMapper接口:
int insertStudentByMap(Map<String,Object> map);
- StudentMapper.xml
<insert id="insertStudentByMap" parameterType="map">insert into t_student(id,name,age,sex,birth,height) value (null,#{姓名},#{年龄},#{性别},#{生日},#{身高})</insert>
- 测试
@Testpublic void InsertStudentByMap(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Map<String,Object> map = new HashMap<>();map.put("姓名","麻瓜");map.put("年龄",25);map.put("身高",1.82);map.put("性别",'男');map.put("生日",new Date());mapper.insertStudentByMap(map);sqlSession.commit();sqlSession.close();}
10.3 实体类参数(POJO参数)
使用实体类参数这里需要注意的是:#{} 里面写的是属性名字。这个属性名其本质上是:set/get方法名去掉set/get之后的名字
- StudentMapper.xml
<insert id="insertStudentByPOJO">insert into t_student(id,name,age,sex,birth,height) value (null,#{name},#{age},#{sex},#{birth},#{height})</insert>
- StudentMapper接口
/** @description: 保存学生信息,通过实体类参数* @param student* @version 1.0*/int insertStudentByPOJO(Student student);
- 测试
@Testpublic void InsertStudentByPOJO(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = new Student();student.setName("小老板");student.setAge(24);student.setSex('男');student.setBirth(new Date());student.setHeight(1.78);mapper.insertStudentByPOJO(student);sqlSession.commit();sqlSession.close();}
10.4 多参数
需求:通过name和sex查询
- StudentMapper.xml
<select id="selectByNameAndSex" resultType="Student">select * from t_student where name = #{name} and sex = #{sex}</select>
- StudentMapper接口
/** 这是多参数* 根据name和sex查询Student信息* 如果是多个参数的话,mybatis框架底层是怎么做到的呢?* mybatis框架会自动创建一个Map集合,并且Map集合是以这种方式储存参数的:* map.put("arg0",name);* map.put("arg1",sex);* map.put("arg1",sex);* map.put("param1",name);* map.put("param2",sex);*/List<Student> selectByNameAndSex(String name,Character sex);
- 测试
@Testpublic void selectByNameAndSex(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> students = mapper.selectByNameAndSex("张三", '男');students.forEach(student -> System.out.println(student));sqlSession.commit();sqlSession.close();}
异常信息描述了:name参数找不到,可用的参数包括[arg1, arg0, param1, param2]
修改StudentMapper.xml配置文件:尝试使用[arg1, arg0, param1, param2]去参数
- 修改StudentMapper.xml文件
<select id="selectByNameAndSex" resultType="Student"><!-- select * from t_student where name = #{name} and sex = #{sex} -->select * from t_student where name = #{arg0} and sex = #{param2}</select>
- 再次尝试修改StudentMapper.xml文件
<select id="selectByNameAndSex" resultType="Student"><!--select * from t_student where name = #{name} and sex = #{sex}--><!--select * from t_student where name = #{arg0} and sex = #{arg1}--><!--select * from t_student where name = #{param1} and sex = #{param2}-->select * from t_student where name = #{arg0} and sex = #{param2}
</select>
通过测试可以看到:
- arg0 是第一个参数
- param1是第一个参数
- arg1 是第二个参数
- param2是第二个参数
实现原理:实际上在mybatis底层会创建一个map集合,以arg0/param1为key,以方法上的参数为value,例如以下代码:
Map<String,Object> map = new HashMap<>();
map.put("arg0", name);
map.put("arg1", sex);
map.put("param1", name);
map.put("param2", sex);// 所以可以这样取值:#{arg0} #{arg1} #{param1} #{param2}
// 其本质就是#{map集合的key}
注意:使用mybatis3.4.2之前的版本时:要用#{0}和#{1}这种形式。
10.5 @Param注解(命名参数)
可以不用arg0 arg1 param1 param2吗?这个map集合的key我们自定义可以吗?当然可以。使用@Param(" 注解的名称 ")
注解即可。这样可以增强可读性。
需求:根据name和age查询
- StudentMapper接口
/** Param注解** mybatis框架底层的实现原理:* map.put("name",name);* map.put("sex",sex);* @param name* @param sex**/List<Student> selectByNameAndSex2(@Param("name")String name,@Param("sex") Character sex);
- StudentMapper.xml
<select id="selectByNameAndSex2" resultType="Student"><!-- 使用了@Param注解之后,arg0和arg1失效了,但是param1和param2还可以用 -->select * from t_student where name = #{name} and sex and #{sex}</select>
- 测试
@Testpublic void SelectByNameAndSex2(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> students = mapper.selectByNameAndSex2("张三", '男');students.forEach(student -> System.out.println(student));sqlSession.commit();sqlSession.close();}
核心:@Param(“这里填写的其实就是map集合的key”)
10.6 @Param注解源码分析
做个了解
十一 小黑子的MyBatis查询专题
模块名:mybatis-007-select
打包方式:jar
引入依赖:mysql驱动依赖、mybatis依赖、logback依赖、junit依赖。
引入配置文件:jdbc.properties、mybatis-config.xml、logback.xml
创建pojo类:Car
创建Mapper接口:CarMapper
创建Mapper接口对应的映射文件:com/powernode/mybatis/mapper/CarMapper.xml
创建单元测试:CarMapperTest
拷贝工具类:SqlSessionUtil
11.1 返回Car
当查询的结果,有对应的实体类,并且查询结果只有一条时:
- CarMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.CarMapper"><select id="selectById" resultType="Car">selectid,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefrom t_carwhereid = #{id}</select></mapper>
- CarMapper接口
package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;public interface CarMapper {/*** 根据id主键查询:结果最多只有一条* @param id* @return*/Car selectById(Long id);}
- 测试
package com.powernode.mybatis.test;import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;public class CarMapperTest {@Testpublic void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = mapper.selectById(1L);System.out.println(car);sqlSession.commit();sqlSession.close();}}
当返回记录结果有多条,却用单个实体类接收时:
- CarMapper接口
/** @description: 根据品牌进行模糊查询* 查询的结果可能有多个,但是采用一个POJO对象来接收的问题* @param brand* @version 1.0*/Car selectByBrandLike(String brand);
- CarMapper.xml
<select id="selectByBrandLike" resultType="Car">selectid,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefrom t_carwherebrand like "%"#{brand}"%"</select>
- 测试
@Testpublic void testSelectByBrandLike(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);//出现异常TooManyResultsException//什么意思?你期望的结果是返回一条记录,但是实际的SQL语句在执行的时候,返回的记录条数不是一条,是多条Car car = mapper.selectByBrandLike("byd");System.out.println(car);sqlSession.commit();sqlSession.close();}
11.2 返回List< Car >
一、采用List集合接收多条数据,模糊查询
- CarMappper接口
List<Car> selectByBrandLike2(String brand);
- CarMapper.xml
<select id="selectByBrandLike2" resultType="Car">selectid,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefrom t_carwherebrand like "%"#{brand}"%"</select>
- 测试
@Testpublic void testSelectByBrandLike2(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectByBrandLike2("byd");cars.forEach(car -> System.out.println(car));sqlSession.commit();sqlSession.close();}
二、
根据id查询Car,id是主键。这个结果一定是一条,不可能有多条数据。所以返回可以用List< Car >
集合进行接收。
- CarMapper.xml
<select id="selectById2" resultType="Car">selectid,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefrom t_carwhereid = #{id}</select>
- CarMapper接口
/** @description: 根据id查询Car,id是主键。这个结果一定是一条,不可能有多条数据。* @param id* @version 1.0*/List<Car> selectById2(Long id);
- 测试
@Testpublic void testSelectById2(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectById2(2L);System.out.println(cars);sqlSession.commit();sqlSession.close();}
11.3 返回Map
当返回的数据,没有合适的实体类对应的话,可以采用Map集合接收。字段名做key,字段值做value。
查询如果可以保证只有一条数据,则返回一个Map集合即可。
- CarMappper.xml
<!-- resultType="java.util.map"有别名 map --><select id="selectByIdRetMap" resultType="map">select * from t_car where id = #{id}</select>
- CarMapper接口
/** @description: 根据id获取汽车信息。将汽车信息放到Map集合中* @param id* @version 1.0*/Map<String,Object> selectByIdRetMap(Long id);
- 测试
@Testpublic void testSelectByIdRetMap(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Map<String, Object> car = mapper.selectByIdRetMap(34L);System.out.println(car);sqlSession.commit();sqlSession.close();}
11.3.1 返回List< Map >
查询结果条数大于等于1条数据,则可以返回一个存储Map集合的List集合
resultMap=“map”,这是因为mybatis内置了很多别名。【参见mybatis开发手册】
- CarMapper.xml
<!-- 这个resultType不是list,是map--><select id="selectAllRetListMap" resultType="map">select * from t_car</select>
- CarMapper接口
/** 查询所有的Car信息,返回一个存放Map集合的List集合* @version 1.0*/List<Map<String,Object>> selectAllRetListMap();
- 测试
@Testpublic void testSelectAllRetListMap(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Map<String, Object>> maps = mapper.selectAllRetListMap();maps.forEach(map -> System.out.println(map));sqlSession.commit();sqlSession.close();}
当然,如果返回一个Map集合,可以将Map集合放到List集合中吗?当然可以,这里就不再测试了。
反过来,如果返回的不是一条记录,是多条记录的话,只采用单个Map集合接收,这样同样会出现之前的异常:TooManyResultsException
11.4 返回Map<String.Map>
拿Car的id做key,以后取出对应的Map集合时更加方便
- CarMapper接口
/** 查询所有的Car,返回一个大Map集合* Map集合的key是每条记录的主键值* map集合的value是每条记录*/@MapKey("id")//将查询结果的id值作为整个大Map集合的keyMap<Long,Map<String,Object>> selectAllRetMap();
- 测试
@Testpublic void testSelectAllRetMap(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Map<Long, Map<String, Object>> maps = mapper.selectAllRetMap();System.out.println(maps);sqlSession.commit();sqlSession.close();}
- CarMapper.xml
<select id="selectAllRetMap" resultType="map">select * from t_car</select>
返回结果一个大Map集合:
{1={car_num=1001, id=1, guide_price=10, produce_time=2022-10-11, brand=宝马520, car_type=燃油车},
2={car_num=1111, id=2, guide_price=10, produce_time=2020-11-11, brand=byd, car_type=电车},
34={car_num=9991, id=34, guide_price=40, produce_time=2022-11-11, brand=凯迪, car_type=能源车},
3={car_num=1111, id=3, guide_price=10, produce_time=2020-11-11, brand=byd, car_type=电车},
4={car_num=9999, id=4, guide_price=30, produce_time=1999-11-10, brand=magua, car_type=旧能源},
6={car_num=8888, id=6, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车},
7={car_num=8888, id=7, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车},
8={car_num=8888, id=8, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车},
9={car_num=8888, id=9, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车},
10={car_num=8888, id=10, guide_price=30, produce_time=2000-11-66, brand=法克鱿, car_type=捞车},
15={car_num=22222, id=15, guide_price=3, produce_time=2022-10-1, brand=小老板, car_type=新能源}}
11.5 resultMap结果映射
查询结果的列名和java对象的属性名对应不上怎么办?
- 第一种方式:as 给列起别名
- 第二种方式:使用resultMap进行结果映射
- 第三种方式:是否开启驼峰命名自动映射(配置settings)
使用resultMap进行结果映射:
- CarMapper接口
/*** 查询所有Car,使用resultMap进行结果映射* @return*/List<Car> selectAllByResultMap();
- CarMapper.xml
<!--1.专门定义一个结果映射,在这个结果映射当中指定数据库的字段名和Java类的属性名的对应关系2.type属性:用来指定POJO类的类名3.id属性:指定resultMap的唯一标识。这个id将来要在select标签中使用--><resultMap id="carResultMap" type="Car"><!--如果数据库表中有主键,一般都是有主键,要不然不符合数据库设计的第一范式--><!--如果有主键,建议这里配置一个id标签,注意:这不是必须的。但是官方的解释是什么?这样配置可以让mybatis提供效率--><id property="id" column="id"></id><!--property后面接的是POJO类的属性名--><!--column后面接的是数据库的字段名--><result property="carNum" column="car_num" javaType="java.lang.String" jdbcType="VARCHAR"/><!--如果column和property是一样的,这个可以省略。--><!-- <result property="brand" column="brand"/>--><result property="guidePrice" column="guide_price"/><result property="produceTime" column="produce_time"/><result property="carType" column="car_type" javaType="string" jdbcType="VARCHAR"/></resultMap><!--select标签的resultMap属性,用来指定使用哪个结果映射。resultMap后面的值是resultMap的id--><select id="selectAllByResultMap" resultMap="carResultMap">select * from t_car</select>
- 测试
@Testpublic void testSelectAllByResultMap(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectAllByResultMap();cars.forEach(car -> System.out.println(car));sqlSession.commit();sqlSession.close();}
11.5.1 开启驼峰命名自动映射
使用这种方式的前提是:属性名遵循Java的命名规范,数据库表的列名遵循SQL的命名规范。
Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。
SQL命名规范:全部小写,单词之间采用下划线分割。
比如以下的对应关系:
实体类中的属性名 | 数据库表的别名 |
---|---|
carNum | car_num |
carType | car_type |
produceTime | produce_time |
- 如何启用该功能,在mybatis-config.xml文件中进行配置:
<!--放在properties标签后面-->
<settings><setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
- CarMapper接口
/**
* 查询所有Car,启用驼峰命名自动映射
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();
- CarMapper.xml
<select id="selectAllByMapUnderscoreToCamelCase" resultType="car">select * from t_car</select>
- 测试
@Testpublic void testSelectAllByMapUnderscoreToCamelCase (){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectAllByMapUnderscoreToCamelCase();cars.forEach(car -> System.out.println(car));sqlSession.commit();sqlSession.close();}
11.6返回总记录条数
需求:查询总记录条数
- CarMapper.xml
<select id="selectTotal" resultType="Long">select count(*) from t_car</select>
- CarMapper接口
/** @description: 获取Car的总记录条数* @version 1.0*/Long selectTotal();
- 测试
@Testpublic void testSelectTotal(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Long total = mapper.selectTotal();System.out.println(total);sqlSession.commit();sqlSession.close();}
十二 小黑子的动态SQL
什么是动态SQL?
有的业务场景,也需要SQL语句进行动态拼接,例如:
- 批量删除
12.1 if标签
if
标签中test
属性是必须的。if
标签中test
属性的值是false或者true。- 如果
test
是true,则if标签中的sql语句就会拼接。反之,则不会拼接。 test
属性中可以使用的是:- 当使用了
@Param
注解,那么test
中要出现的是@Param
注解指定的参数名。@Param("brand")
,那么这里只能使用brand - 当没有使
在这里插入代码片
用@Param
注解,那么test中要出现的是: param1 param2 param3 arg0 arg1 arg2. . . . - 当使用了POJO,那么
test
中出现的是POJO类的属性名。
- 当使用了
- 在mybatis的动态SQL当中,不能使用&&,只能使用and。
- CarMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.CarMapper"><select id="selectByMultiCondition" resultType="Car">select * from t_carwhere<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>
- CarMapper接口
package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface CarMapper {/** 多条件查询* @param brand* @param guidePrice* @param carType* @version 1.0*/List<Car> selectByMultiCondition(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
}
- 测试
package com.powernode.mybatis.test;import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.List;public class CarMapperTest {@Testpublic void testSelectByMultiCondition(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);//假设三个条件都不是空List<Car> cars = mapper.selectByMultiCondition("byd", 2.0, "电车");cars.forEach(car -> System.out.println(car));sqlSession.commit();sqlSession.close();}
}
12.2 where标签
where
标签的作用:让where
子句更加动态智能。
所有条件都为空时,where
标签保证不会生成where
子句。
自动去除某些条件前面多余的and
或or
。后面的无法去除
继续使用if标签中的需求。
- CarMapper接口
/** @description: where标签,让where子句更加的智能* @version 1.0*/List<Car> selectByMultiConditionWithWhere(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
- CarMapper接口
<select id="selectByMultiConditionWithWhere" resultType="Car">select * from t_car<!--where标签是专门负责where子句动态生成的--><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>
- 测试
@Testpublic void selectByMultiConditionWithWhere(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);//假设三个条件都不是空
// List<Car> cars = mapper.selectByMultiConditionWithWhere("byd", 2.0, "电车");//假设三个条件都是空,where标签可以自动判断是否符合条件
// List<Car> cars = mapper.selectByMultiConditionWithWhere("", null, "");//假设一个条件为空,where标签也会自动判断消去andList<Car> cars = mapper.selectByMultiConditionWithWhere("", 2.0, "电车");cars.forEach(car -> System.out.println(car));//但是后面两个条件是空时,后面有and,where标签就无法去除sqlSession.commit();sqlSession.close();}
12.3 trim标签
trim标签的属性:
- prefix:再trim标签中的语句前添加内容
- suffix:再trim标签中的语句后添加内容
- prefixOverrides:前缀覆盖掉(去掉)
- suffixOverrides:后缀覆盖掉(去掉)
/** @description: 使用trim标签* @version 1.0*/List<Car> selectByMultiConditionWithTrim(@Param("brand") String brand,@Param("guidePrice") Double guidePrice, @Param("carType") String carType);
<select id="selectByMultiConditionWithTrim" resultType="Car"><!--prefix="where" 是在trim标签所有内容的前面添加where--><!--suffixOverrides="and|or" 把trim标签中内容的后缀and或or去掉,以至于后面有and或or的话程序也不会报错-->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>
@Testpublic void testSelectByMultiConditionWithTrim(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectByMultiConditionWithTrim("", null, "");cars.forEach(car -> System.out.println(car));sqlSession.commit();sqlSession.close();}
12.4 set标签
主要使用在update
语句当中,用来生成set
关键字,同时去掉最后多余的“,”
比如我们只更新提交的不为空的字段,如果提交的数据是空或者""
,那么这个字段我们将不更新。
/** @description: 使用set标签* @version 1.0*/int updateBySet(Car car);
<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>whereid = #{id}</update>
@Testpublic void testUpdateBySet(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = new Car(34L, null, "麻瓜霸道", null, null, null);mapper.updateBySet(car);sqlSession.commit();sqlSession.close();}
12.5 chose when otherwise标签
这三个标签是在一起使用的:
语法格式:
<choose><when></when><when></when><when></when><otherwise></otherwise>
</choose>
等同于:
if(){}else if(){}else if(){}else if(){}else{}
只有一个分支会被选择!!!!
案例需求:先根据品牌查询,如果没有提供品牌,再根据指导价查询,如果没有提供指导架构,就根据生产日期查询
/*** 使用choose when otherwise标签查询* @param brand* @param guidePrice* @param carType* @return*/List<Car> selectWithChoose(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
<select id="selectWithChoose" resultType="Car">select * from 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>
@Testpublic void testSelectWithChoose(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);//三个条件都不为空
// List<Car> cars = mapper.selectWithChoose("麻瓜霸道", 1.0, "新能源");//第一个条件是空// List<Car> cars = mapper.selectWithChoose(null, 1.0, "新能源");//前两个条件是空// List<Car> cars = mapper.selectWithChoose(null, null, "新能源");//全都是空List<Car> cars = mapper.selectWithChoose(null, null, null);cars.forEach(car -> System.out.println(car));sqlSession.commit();sqlSession.close();}
12.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','新能源')
12.6.1 批量删除
- 用
in
来删除
foreach标签属性:
- collection:集合或数组
- item:集合或数组中的元素
- separator:循环之间的分隔符
- open:foreach标签中所有内容的开始
- close:foreach标签中所有内容的结束
/*** 通过foreach完成批量删除* @param ids* @return*/int deleteBatchByForeach(@Param("ids") Long[] ids);
<delete id="deleteBatchByForeach">delete from t_car where id in<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach></delete>
@Testpublic void testDeleteBatchByForeach(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Long[] ids = {8L,9L,10L};mapper.deleteBatchByForeach(ids);sqlSession.commit();sqlSession.close();}
- 用or来删除
<delete id="deleteById2" >delete from t_car where<foreach collection="ids" item="id" separator="or">id = #{id}</foreach></delete>
/*** 通过id批量删除,使用or关键字* @param ids* @return*/int deleteById2(@Param("ids") Long[] ids);
@Testpublic void testDeleteById2(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Long[] ids = {35L,36L,37L};int count = mapper.deleteById2(ids);System.out.println(count);sqlSession.commit();sqlSession.close();}
12.6.2 批量插入
<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>
/*** 通过foreach批量插入,一次插入多条car信息* @param cars* @return*/int insertBatch(@Param("cars") List<Car> cars);
@Testpublic void testInsertBatchByForeach(){CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);Car car1 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");Car car2 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");Car car3 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");List<Car> cars = Arrays.asList(car1, car2, car3);int count = mapper.insertBatch(cars);System.out.println("插入了几条记录" + count);SqlSessionUtil.openSession().commit();}
12.7 sql标签和include标签
sql
标签用来声明sql片段
include
标签用来将声明的sql片段包含到某个sql语句当中
作用:代码复用。易维护。
<!--声明一个SQL片段-->
<sql id="carCols">id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
</sql><select id="selectAllRetMap" resultType="map">select <!--将声明的sql片段包含进来--><include refid="carCols"/> from t_car
</select><select id="selectAllRetListMap" resultType="map">select <include refid="carCols"/> carType from t_car
</select><select id="selectByIdRetMap" resultType="map">select <include refid="carCols"/> from t_car where id = #{id}
</select>
相关文章:

小黑子—MyBatis:第四章
MyBatis入门4.0 十 小黑子进行MyBatis参数处理10.1 单个简单类型参数10.1.1 单个参数Long类型10.1.2 单个参数Date类型 10.2 Map参数10.3 实体类参数(POJO参数)10.4 多参数10.5 Param注解(命名参数)10.6 Param注解源码分析 十一 小…...

Docker快速上手:使用Docker部署Drupal并实现公网访问
文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS,适用于各种不同的网站项目,从小型个人博客到大型企业级门户网站。它的学习…...
React知识点系列(1)-每天10个小知识
目录 1.什么是 React,以及它在前端开发中的优势是什么?2.你是如何组织和管理 React 组件的?3.你能解释一下 React 的生命周期方法吗?你通常在哪个生命周期方法中发起网络请求?4.什么是 React Hooks?你常用哪…...
substring 和 substr 的区别
1、结论 两个方法都用于截取字符串,其用法不同: 1)相同点: ① 都用于截取字符串; ② 第一个参数都是表示提取字符的开始索引位置; 2)不同点: ① 第一个参数的取值范围不同&…...
产品经理的工作职责是什么?
产品经理的工作职责主要包括以下几个方面: 1. 产品策划与定义:产品经理负责制定产品的整体策略和规划,包括产品定位、目标用户、市场需求分析等。他们需要与团队合作,定义产品的功能和特性,明确产品的核心竞争力和差异…...

智能井盖传感器:提升城市安全与便利的利器
在智能化城市建设的浪潮中,WITBEE万宾智能井盖传感器,正以其卓越的性能和创新的科技,吸引着越来越多的关注。本文小编将为大家详细介绍这款产品的独特优势和广阔应用前景。 在我们生活的城市中,井盖可能是一个最不起眼的存在。然而…...

给你一个项目,你将如何开展性能测试工作?
一、性能三连问 1、何时进行性能测试? 性能测试的工作是基于系统功能已经完备或者已经趋于完备之上的,在功能还不够完备的情况下没有多大的意义。因为后期功能完善上会对系统的性能有影响,过早进入性能测试会出现测试结果不准确、浪费测试资…...

点燃市场热情,让产品风靡全球——实用推广策略大揭秘!
文章目录 一、实用推广策略的重要性1. 提高产品知名度和认可度2. 拓展产品市场和用户群体3. 增强企业品牌形象和市场竞争力 二、实用推广策略的种类1. 社交媒体推广2. 定向推广3. 口碑营销4. 内容推广 三、实用推广策略的实施步骤1. 研究目标用户和市场需求,明确产品…...

Python操作Hive数据仓库
Python连接Hive 1、Python如何连接Hive?2、Python连接Hive数据仓库 1、Python如何连接Hive? Python连接Hive需要使用Impala查询引擎 由于Hadoop集群节点间使用RPC通信,所以需要配置Thrift依赖环境 Thrift是一个轻量级、跨语言的RPC框架&…...
客户收到报价后突然安静了,怎么办?
外贸人常常会有这样的经历:与意向度很高的客户数封邮件沟通报价之后,突然客户那边就沉静下来了,而不知所措,遇到这样的客户,应该怎么办呢? Vol.1 了解客户信息 首先自身要养成一个好习惯,针对…...
O2OA(翱途)常见知识之 mysql 数据库备份
概述 系统运行一段时间后,可能发生各种情况导致数据丢失,如硬件故障、人为错误、软件错误、病毒攻击等。定期备份可以帮助您保护数据免受这些风险的影响,以便在需要时能够恢复数据。 O2OA应用本身可以通过dump配置每天自定备份数据ÿ…...
如何让你的程序支持lua脚本
最近做了一个控制机械臂的程序,使用C语言开发的,调试的时候总是需要修改代码来调整运动轨迹, 总是要编译,实在烦人 不过有个方法就是使用lua来调试运动逻辑 代码如下 static int lua_up(lua_State*l) {size_t stepluaL_checkinteger(l,1);//向上动作up(step);return 0; }st…...

什么是系统架构师?什么是系统架构?
1. 什么是系统架构师? 系统架构设计师(System Architecture Designer)是项目开发活动中的关键角色之一。系统架构是系统的一种整体的高层次的结构表示,是系统的骨架和根基,其决定了系统的健壮性和生命周期的长短。 系统架构设计…...

大数据NoSQL数据库HBase集群部署
目录 1. 简介 2. 安装 1. HBase依赖Zookeeper、JDK、Hadoop(HDFS),请确保已经完成前面 2. 【node1执行】下载HBase安装包 3. 【node1执行】,修改配置文件,修改conf/hbase-env.sh文件 4. 【node1执行】…...

百乐钢笔维修(官方售后,全流程)
文章目录 1 背景2 方法3 结果 1 背景 在给钢笔上墨的途中,不小心总成掉地上了,把笔尖摔弯了(虽然还可以写字,但是非常的挂纸),笔身没有什么问题,就想着维修一下笔尖或者替换一下总成。 一般维…...

Redis 介绍安装
数据库 关系型数据库 关系型数据库是一个结构化的数据库,创建在关系模型(二维表格模型)基础上,一般面向于记录。 SQL 语句(标准数据查询语言)就是一种基于关系型数据库的语言,用于执行对关系型…...

MyCat管理及监控
MyCat原理 在 MyCat 中,当执行一条 SQL 语句时, MyCat 需要进行 SQL 解析、分片分析、路由分析、读写分离分析等操作,最终经过一系列的分析决定将当前的SQL 语句到底路由到那几个 ( 或哪一个 ) 节点数据库,数据库将数据执行完毕后…...

滑动窗口算法题
更新结果 1、判断条件成立后更新结果 2、入窗口后即可更新结果 判断: 出窗口后状态更新,循环回去再判断。 1、长度最小的子数组 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台...

部署zabbix代理服务器、部署zabbix高可用集群
目录 部署zabbix代理服务器 1、环境设置 2、设置 zabbix 的下载源,安装 zabbix-proxy 3、配置Mariadb yum源,并下载marisdb数据库 4.、启动数据库,并初始化数据库 5、登录数据库,创建数据库并指定字符集,并进行…...

[stm32]外中断控制灯光
在STM32CubeMX中配置外部中断功能和参数 1、将上拉输入的引脚设置为:GPIO_EXTI功能 2、GPIO模式设为下降沿触发外部中断,使能上拉电阻,用户标签 3、要将NVIC的相关中断勾选 只有将中断源进行勾选,相关的中断请求才能得到内核的…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...
Python爬虫实战:研究Restkit库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...