1.动态SQL的概念
动态sql是指在进行sql操作的时候,传入的参数对象或者参数值,根据匹配的条件,有可能需要动态的去判断是否为空,循环,拼接等情况;
2.mybatis动态sql
1-if判断:
<!--
BookMapper.xml
id:调用的方法名
-->
<select id="queryBookByIf" resultType="com.zking.mybatis01.model.Book">
<!--
SQL语句;
<include refid="Base_Column_List"/>:数据库表中所有的字段;
-->
select <include refid="Base_Column_List"/> from t_book where 1=1
<!-- if判断book参数条件 -->
<if test="null!=bookType and ''!=bookType">
<!-- #{bookType}:拿到实体类中的参数,book_type:数据库中的字段名!!! -->
and book_type=#{bookType}
</if>
</select>
2-trim: mybatis中trim是动态拼接;java中表示去除前后空格
trim中主要运用SQL语句的动态拼接,所做到的SQL使用的方便性
<!--
动态拼接的insert
id:调用的方法名
prefix:前缀;
prefixOverrides:去除前缀的指定的字符;
suffix:后缀;
suffixOverrides:去除后缀的指定的字符;
-->
<insert id="insertSelective" parameterType="com.zking.mybatis01.model.Book" >
insert into t_book
<trim prefix="(" suffix=")" suffixOverrides="," prefixOverrides="">
<if test="bookId != null" >
book_id,
</if>
<if test="bookName != null" >
book_name,
</if>
<if test="bookNamePinyin != null" >
book_name_pinyin,
</if>
<if test="bookPrice != null" >
book_price,
</if>
<if test="bookType != null" >
book_type,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="bookId != null" >
#{bookId,jdbcType=INTEGER},
</if>
<if test="bookName != null" >
#{bookName,jdbcType=VARCHAR},
</if>
<if test="bookNamePinyin != null" >
#{bookNamePinyin,jdbcType=VARCHAR},
</if>
<if test="bookPrice != null" >
#{bookPrice,jdbcType=REAL},
</if>
<if test="bookType != null" >
#{bookType,jdbcType=VARCHAR},
</if>
</trim>
</insert>
使用junit测试:
@Test
public void demo() {
//赋值参数
book.setBookName("傻狗传说");
book.setBookType("冥想");
book.setBookPrice(100f);
//调用方法
bookService.insertSelective(book);
}
控制台看打印结果:通过对象中的属性动态SQL
3-foreach:可以和trim嵌套使用
定义Bookvo用于foreach循环
public class BookVo extends Book {
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
映射XMLforeach: 和拼接差不多,相当于是循环拼接
<select id="queryBookByForeach" resultType="com.zking.mybatis01.model.Book">
select <include refid="Base_Column_List"/> from t_book where 1=1 and book_id in
<!--
相当于:for(Integer id : ids)
separator:分隔符;
open:打开位置;
close:结束位置;
-->
<foreach collection="ids" item="id" separator="," open=" (" close=")">
#{id}
</foreach>
</select>
使用junit测试:
@Test
public void demo() {
BookVo vo = new BookVo();
//将数组转为集合
vo.setIds(Arrays.asList(new Integer[]{100,101,14937}));
List<Book> books = bookService.queryBookByForeach(vo);
books.forEach(System.out::println);
}
执行的SQL语句:
返回打印的数据:
4-where查询条件:
查询的时候如果第一个条件不存在,则可能会出现将后面 “and xxx” 拼接到sql语句中,造成sql 语法错误。
使用<where>标签代替sql查询条件的"WHERE"
修改sql映射文件:<where>标签会根据条件自动消除掉sql语句中前面部分的"AND" 字符
<select id="queryBookByIf" resultType="com.zking.mybatis01.model.Book">
select <include refid="Base_Column_List"/> from t_book where 1=1
<where>
<if test="null!=bookType and ''!=bookType">
and book_type=#{bookType}
</if>
</where>
</select>
5-choose (when, otherwise)标签:
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。而使用if标签时,只要test中的表达式为 true,就会执行 if 标签中的条件。MyBatis 提供了 choose 元素。if标签是与(and)的关系,而 choose 是或(or)的关系。
choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
<!-- choose(判断参数) - 按顺序将实体类 Book 第一个不为空的属性作为:where条件 -->
<select id="queryBookByChoose" resultType="com.zking.mybatis01.model.Book">
select <include refid="Base_Column_List"/> from t_book where 1 = 1
<choose>
<when test="bookName != null">
and book_name = #{bookName}
</when>
<when test="bookType != null">
and book_type = #{bookType}
</when>
<!-- otherwise:设置的default,when条件都不成立的时候才会使用 -->
<otherwise>
and book_id = 100
</otherwise>
</choose>
</select>
测试:
public void demo() {
//俩行关键代码段
// book.setBookName("西游记");
// book.setBookType("金典");
List<Book> books = bookService.queryBookByChoose(book);
books.forEach(System.out::println);
}
当以上代码段被注释时:
当以上代码段不被注释时: (有俩个不为null,但是只有一个使用了进去,如果有一个成立,则 choose 结束)
当when条件成立则不会使用到otherwise的SQL语句,
当when条件不成立则会使用到otherwise的SQL语句。
按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。
6-传参
单个参数传参:列如void query(Integer id);映射文件中可以用value来取值
String传参:String是不能用value的,必须使用void query(@Param("bookType") String bookType);:@Param("bookType")方式,并且指明参数名,参数名‘bookType’用于取值
集合List传参:使用List集合中对象的属性名取值,并非数据库表中的字段名
多个参数传参:void query(@Param("bookType") String bookType,@Param("bookId") Integer bookId);:和String传参一个道理
--- 一般为了方便使用建议用对象或者集合传参 ---
7-select查询返回的结果集:
resultType:适合使用返回值的数据类型是非自定义的,即jsk的提供的类型
resultMap:适合使用返回值是自定义实体类的情况,
映射文件 resultType="java.util.Map":返回Map集合,List<Map,Object>和Map集合适用于多表联查和综合的数据结果
8-原始时代版 分页查询:
提前准备PageBean.java,分页查询的基本在Mapper类中不需要传入pagebean,由内置插件帮我们完成,到Service类就要pagebean参数了,
@Test
public void demo() {
//分页查询
PageBean pagebean = new PageBean();
//判断是否分页
if(null!=pagebean && pagebean.isPagination()){
//参数1:当前页码;参数2:每页条数;
PageHelper.startPage(pagebean.getPage(),pagebean.getRows());
}
List<Book> books = bookService.queryBookPager(Book.builder().build(), pagebean);
System.out.println(books.getClass());
if(null!=pagebean && pagebean.isPagination()){
PageInfo pageInfo = new PageInfo(books);
System.out.println("页码:"+pageInfo.getPageNum());
System.out.println("页大小:" + pageInfo.getPageSize());
System.out.println("总记录:" + pageInfo.getTotal());
List list = pageInfo.getList();
list.forEach(System.out::println);
}
}
如果想要达到其他分页效果就给PageBean对象属性进行操作