技术文章

Mybatis之动态SQL及映射结果(带你了解动态SQL的魅力)

君易--鑨

An editor at Blogzine


  • 2023-08-24
  • 41天前
  • 2696
  • 17 Views
  • 100

目录

前言

一、Mybatis之动态SQL

1. 简介

2. 作用及重要性

 3. 应用场景

二、动态SQL讲解

1. 原生使用工具类(BaseDao)的SQL

2. 运用动态SQL编写方法

2.1 Mybatis动态SQL的常用标签

2.2 Mybatis动态SQL的常用函数

2.3 案例展示

if标签的运用

foreach标签的运用

三、动态SQL之模糊查询

1. 模糊查询的三种写法

BookMapper.xm

在接口类和接口实现编写方法

测试类代码

测试结果

2.#符和$符的区别(面试题)

四、Mybatis中的结果映射

(1)场景模拟及使用的结果映射

1.返回单表的对应的实体类,仅又一个查询结果(可以用resultType/resultMap)

2.返回单表的对应的实体类,有多个查询结果(可以用resultType/resultMap)

3.返回多表的对应结果,仅有一个查询结果(通常用resultType,也可以用resultMap)

4.返回多表的对应结果,有多个查询结果(通常用resultType,也可以用resultMap)

5.返回单个列段,仅有一个查询结果(就用resultType)

6.返回单个列段,有多个查询结果(就用resultType)

(2)resultType与resultMap的区别


前言

在前面的一期博客中我们分享了有关Mybatis入门简介及用Mybatis模拟测试一些相关数据库数据操作的功能,这一期博客我继续为大家分享有关Mybatis的相关知识点,今天我分享的内容是Mybatis之动态SQL及映射结果。请老铁们仔细阅读。

一、Mybatis之动态SQL

1. 简介

  • MyBatis中的动态SQL是一种在SQL语句中根据条件动态生成不同部分的技术。它允许我们根据不同的条件来构建不同的SQL语句,从而实现更灵活的查询和更新操作。
  • 在MyBatis中,我们可以使用动态SQL来处理各种情况,例如根据不同的条件拼接WHERE子句、根据条件选择不同的列、根据条件判断是否包含某个元素等等。
  • MyBatis提供了一些标签和函数来实现动态SQL,其中最常用的是if、choose、when、otherwise和foreach标签。通过使用这些标签,我们可以根据条件来动态生成SQL语句的不同部分。

2. 作用及重要性

  1. 生成SQL语句具有灵活性:动态SQL允许根据不同的条件来生成不同的SQL语句,从而实现动态查询和更新操作。这样我们可以根据项目框架需求灵活地构造所需的SQL语句,避免了不需要硬编码的情况出现。

  2. 使SQL语句清晰易懂(可读性):使用动态SQL可以使SQL语句更加清晰易读。通过使用内置携带的函数与标签,根据条件组织SQL语句的不同部分,从而避免大量的SQL嵌套与重复。它使SQL语句更加直观,更有利于开发人员理解及维护

  3. 具有较强的扩展性:动态SQL提供了一种扩展SQL语句的方式,允许我们根据需求加、修改或删除查询条件。这种扩展性使得我们能够轻松地改变和优化SQL语句,而不需要修改大量的固定SQL代码。这样大大减少了开发使用的时间,提高了开发效率及后期的维护效率。

  4. 性能优化:通过使用动态SQL,我们可以根据不同的条件动态生成SQL语句,从而避免不必要的查询或更新操作。例如,我们可以根据用户的选择动态生成查询条件, 只查询真正需要的数据,减少了不必要的数据库操作,提高了系统性能

 3. 应用场景

Mybatis的应用场景
应用场景说明
条件查询当需要根据不同的条件进行查询时,可以使用动态SQL来根据条件动态拼接WHERE子句。比如在一个用户管理系统中,可以根据用户的姓名、性别、年龄等条件来进行灵活的查询。
动态排序当需要根据不同的字段进行排序时,可以使用动态SQL来动态生成ORDER BY子句。比如在一个商品列表中,用户可以选择按照价格、销量等字段进行排序。
动态更新当需要根据不同的条件来进行更新操作时,可以使用动态SQL来根据条件动态生成UPDATE语句。比如在一个订单系统中,可以根据订单状态、支付状态等条件来更新订单信息。
动态插入当需要根据不同的条件来进行插入操作时,可以使用动态SQL来根据条件动态生成INSERT语句。比如在一个用户注册系统中,可以根据用户的选择来插入不同的用户信息。
复杂逻辑处理当需要根据复杂的业务逻辑来生成SQL语句时,可以使用动态SQL来处理复杂的逻辑判断和条件拼接。比如在一个电商系统中,根据不同的促销活动和用户等级来生成不同的优惠查询条件。 
批量操作当需要对多个对象进行批量操作时,可以使用动态SQL来生成批量操作的SQL语句。比如批量插入多个用户数据或批量删除多个订单数据。

二、动态SQL讲解

1. 原生使用工具类(BaseDao)的SQL

//模拟原生编写数据库访问方法
BaseDao.java
     excuteUpdate(sql,book,attrs)
     String sql=update t_mvc_book set bname =?,price = ? where bid =?
//  此时假如前台jsp传参到后台,没有传递bname值,那么造成的结果如下
    update t_mvc_book set bname =null price =33 where bid =3

弊端:会将没有传参的字段值改为null,违背了我们编码的初衷。

2. 运用动态SQL编写方法

2.1 Mybatis动态SQL的常用标签

常用标签
标签使用说明
<if>条件判断标签,根据指定的条件来决定是否生成对应的SQL语句片段
<choose><when><otherwise>类似于Java中的switch语句,根据不同的条件来选择生成不同的SQL语句片段。
<trim>用于去除或补齐SQL语句片段的开头和结尾的空格,可以用于拼接包含可选条件的SQL语句。
<where>用于拼接WHERE子句,自动处理WHERE关键字和添加适当的AND或OR连接条件。
<set>用于拼接UPDATE语句的SET子句,自动处理SET关键字和添加适当的逗号分隔更新字段。
<foreach>用于循环遍历集合或数组,并在SQL语句中插入对应的元素作为参数。可以指定开始位置、结束位置、分隔符等属性。
<bind>用于将一个常量绑定到一个变量上,在后续的SQL语句中使用该变量。 这些标签在Mybatis中可以帮助我们根据不同的条件动态生成SQL语句,使得我们可以更加灵活地构建查询和更新语句。

2.2 Mybatis动态SQL的常用函数

常用函数
函数函数说明
trim()去除字符串的开头或结尾指定字符(默认为空格)。 例子:<trim prefixOverrides="AND |OR ">...</trim>
concat()拼接多个字符串。 例子:${param1} + ' ' + ${param2}
substring()截取字符串的一部分。 例子:SUBSTRING(column_name, start_index, length)
lower()将字符串转换为小写。 例子:LOWER(column_name)
upper()将字符串转换为大写。 例子:UPPER(column_name)
replace()替换字符串中的某个字符或字符串。 例子:REPLACE(column_name, old_string, new_string)
length()获取字符串的长度。 例子:LENGTH(column_name)
now()获取当前时间。 例子:NOW()
date_format()格式化日期。 例子:DATE_FORMAT(column_name, pattern)

2.3 案例展示

if标签的运用

foreach标签的运用

场景

//假设编写的SQL语句如下所示
   delete* from t_oa_permission where id in (...)
//其中括号里的是条件,也是前台需要传过来的参数
//有些时候我们前台会传一个字符串过来(如下所示)
  1,2,3,4,5,6
//像我们在删除购物车的时候,我们一般会这样写
    for int id : ids
     orderItemsDao.delete(id);
//这么写的目的只是懒得拼接SQL语句
    delete* from t_oa_permission where id in ( 1,2,3,4,5,6)
//  如果我们要上上面那样去编写代码的话
//  首先实例化Stringbuffer类来读取字符串
    Stringbuffer sb=new Stringbuffer();
 // 然后对其进行一系列操作
    sb.append(",").append(id)
   //进行选择性的截取
    sb.substring(1)

//由此而知,我们如果按照上述方式编写代码的话会需要花费人力资源和时间精力,
//这并不利于我们大大提高我们自身的开发效率;
//而且该方式对SQL语句处理较为复杂,过程繁琐。

BookMapper.xml(编写方法)

<?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.yx.mapper.BookMapper" >
  <resultMap id="BaseResultMap" type="com.yx.model.Book" >
    <constructor >
      <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="price" jdbcType="REAL" javaType="java.lang.Float" />
    </constructor>
  </resultMap>
  <sql id="Base_Column_List" >
    bid, bname, price
  </sql>

  <select id="selectByBids" resultType="com.yx.model.Book" parameterType="java.util.List" >
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bid in
    <foreach collection="bids" item="bid" open="(" close=")" separator=",">
        #{bid}
    </foreach>

  </select>

</mapper>

在接口类和接口实现编写方法

package com.yx.biz;

import com.yx.model.Book;

import java.util.List;

public interface BookBiz {

    List<Book> selectByBids(List bids);
}


//========================以上是接口类的代码=====================
//==========================以下是接口实现类的代码==========================

package com.yx.biz.Impl;

import com.yx.biz.BookBiz;
import com.yx.mapper.BookMapper;
import com.yx.model.Book;

import java.util.List;

/**
 * @author 君易--鑨
 * @site www.yangxin.com
 * @company 木易
 * @create  2023-08-21 10:15
 */
public class BookBizImpl implements BookBiz {

    @Override
    public List<Book> selectByBids(List bids) {
        return bookMapper.selectByBids(bids);
    }

}

//==========================以下是BookMapper 的代码==========================

package com.yx.mapper;

import com.yx.model.Book;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface BookMapper {


    List<Book> selectByBids(@Param("bids") List bids);

}

测试类代码

 @Test
    //   测试方法
    public void testByid(){
        System.out.println("测试使用foreach标签的方法...");
        List<Integer> bids = Arrays.asList(new Integer[]{55, 56, 57, 58, 59, 60});
          bookBiz.selectByBids(bids).forEach(System.out::println);//jdk1.8的新特性。
//       打印输出
    }

输出结果

三、动态SQL之模糊查询

1. 模糊查询的三种写法

BookMapper.xm

<?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.yx.mapper.BookMapper" >
  <resultMap id="BaseResultMap" type="com.yx.model.Book" >
    <constructor >
      <idArg column="bid" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="bname" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="price" jdbcType="REAL" javaType="java.lang.Float" />
    </constructor>
  </resultMap>
  <sql id="Base_Column_List" >
    bid, bname, price
  </sql>

<!--  #字符号-->
  <select id="like01" resultType="com.yx.model.Book" parameterType="java.lang.String">
    select 
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bname like #{bname}
  </select>

<!--  $符号-->
  <select id="like02" resultType="com.yx.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bname like ${bname}
  </select>

<!--  concat-->
  <select id="like03" resultType="com.yx.model.Book" parameterType="java.lang.String">
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bname like concat('%',#{bname},'%')
  </select>



</mapper>

在接口类和接口实现编写方法

package com.yx.mapper;

import com.yx.model.Book;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface BookMapper {

//#
    List<Book> like01(@Param("bname") String bname);
//$
    List<Book> like02(@Param("bname") String bname);
//concat
    List<Book> like03(@Param("bname") String bname);
}
//===============以上是BookMapper的代码========================
//===============以下是方法接口的代码========================
package com.yx.biz;

import com.yx.model.Book;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface BookBiz {
  
    //#
    List<Book> like01(@Param("bname") String bname);
    //$
    List<Book> like02(@Param("bname") String bname);
    //concat
    List<Book> like03(@Param("bname") String bname);


}

//===============以下是方法接口实现类的代码========================
package com.yx.biz.Impl;

import com.yx.biz.BookBiz;
import com.yx.mapper.BookMapper;
import com.yx.model.Book;

import java.util.List;

/**
 * @author 君易--鑨
 * @site www.yangxin.com
 * @company 木易
 * @create  2023-08-21 10:15
 */
public class BookBizImpl implements BookBiz {
//    调用代码生成器的接口
    BookMapper bookMapper;

    public BookMapper getBookMapper() {
        return bookMapper;
    }

    public void setBookMapper(BookMapper bookMapper) {
        this.bookMapper = bookMapper;
    }


    @Override
    public List<Book> like01(String bname) {
        return bookMapper.like01(bname);
    }

    @Override
    public List<Book> like02(String bname) {
        return bookMapper.like02(bname);
    }

    @Override
    public List<Book> like03(String bname) {
        return bookMapper.like03(bname);
    }
}

测试类代码

package com.yx.Demo;

import com.yx.biz.BookBiz;
import com.yx.biz.Impl.BookBizImpl;
import com.yx.mapper.BookMapper;
import com.yx.model.Book;
import com.yx.untils.SessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

/**
 * @author 君易--鑨
 * @site www.yangxin.com
 * @company 木易
 * @create  2023-08-21 10:26
 * 测试增删改查的方法
 */
public class Dmeo1 {
//    实例化工具类和业务层类
    private SqlSession sqlSession;
    private BookBiz bookBiz;

    @Before
    public void a(){
        System.out.println("执行测试代码块之前会执行的初始化代码块......");
//        获取session对象
       sqlSession=SessionUtil.openSession();
        BookBizImpl bookBiz=new BookBizImpl();
//        获取BookMapper对象
        BookMapper mapper=sqlSession.getMapper(BookMapper.class);
//        将获取到的BookMapper对象添加到bookBiz中
        bookBiz.setBookMapper(mapper);
//        扩大作用权限
        this.bookBiz=bookBiz;
    }

    @After
    public void b(){
        System.out.println("执行测试代码块之后会执行的初始化代码块......");
//   提交数据库提交事务
        sqlSession.commit();
    }

    @Test
    //   测试方法
    public void testlike01(){
        System.out.println("测试like01方法...");
        bookBiz.like01("%圣墟%").forEach(System.out::println);//jdk1.8的新特性。
    }

    @Test
    //   测试方法
    public void testlike02(){
        System.out.println("测试like01方法...");
        bookBiz.like02("%圣墟%").forEach(System.out::println);//jdk1.8的新特性。
    }

    @Test
    //   测试方法
    public void testlike03(){
        System.out.println("测试like01方法...");
        bookBiz.like03("%圣墟%").forEach(System.out::println);//jdk1.8的新特性。
    }
}

测试结果

#字符编写方法的测试效果

$字符编写方法的测试效果

运用concat编写的方法测试结果

注意事项:

  • 如果运用了$字符编写了模糊查询的方法,在方法语句体中${参数字段}未用单引号包裹则会报错,SQL编写错误如下图所示

2.#符和$符的区别(面试题)

  1. $是占位符传参,#是预处理SQL
  2. 在外在形式,$传参不带引号,#传参自带引号     
  3. $传参存在SQL注入,#不存在
  4. $可以用来做动态列,完成动态SQL开发

四、Mybatis中的结果映射

使用mybatis的各种场景,返回的结果是多样的,resultType与resultMap有什么区别 请看下面模拟。

(1)场景模拟及使用的结果映射

1.返回单表的对应的实体类,仅又一个查询结果(可以用resultType/resultMap)

2.返回单表的对应的实体类,有多个查询结果(可以用resultType/resultMap)

3.返回多表的对应结果,仅有一个查询结果(通常用resultType,也可以用resultMap)

4.返回多表的对应结果,有多个查询结果(通常用resultType,也可以用resultMap)

5.返回单个列段,仅有一个查询结果(就用resultType)

6.返回单个列段,有多个查询结果(就用resultType)

(2)resultType与resultMap的区别

  • resultType:对应的是返回类型
  • resultMap:对应的是返回映射关系,指的是实体类与数据库表字段的关系。

通常而言,单表查询,返回单列,返回多表查询结果,使用resultType。

如果查询的结果,需要使用关联属性的体现,那么使用resultMap。

resultType适用于简单的映射需求,而resultMap适用于更复杂的映射需求,可以定义更灵活的映射规则。根据具体的需求和情况,选择合适的映射方式非常重要。

我的分享到这里就结束了,感兴趣的老铁点赞加关注,后续我会继续与老铁们分享 

一波三连,拜托拜托

版权声明:

本文为[君易--鑨]所创,转载请带上原文链接,感谢

https://blog.csdn.net/weixin_74352229/article/details/132420188


评论数 0



留下回复

如果您是个网络喷子或者键盘侠,那么建议您多看少说。