Mybatis之动态SQL及映射结果

简介: Mybatis之动态SQL及映射结果

一.动态sql

1.1.什么是动态SQL

动态SQL是一种在运行时构建和执行SQL语句的方法。通常情况下,SQL语句是在编译时确定的,但是动态SQL允许在程序运行时根据特定条件或者用户输入来构建SQL语句。这样可以使得SQL语句更加灵活和可变化。动态SQL可以用于实现动态的搜索、过滤和排序等功能。它在很多编程语言和数据库中都有支持,比如Java的JDBC、Python的SQLAlchemy等。需要注意的是,动态SQL在使用时需要注意防止SQL注入攻击,确保输入的数据正确地转义和验证。

1.2.动态SQL的好处

  1. 动态性:可以根据不同的条件和需求构建不同的SQL语句,使得查询和操作更加具有灵活性。可以根据用户的输入动态生成SQL语句,实现动态搜索、过滤、排序等功能。
  2. 可重用性:通过使用动态SQL,可以减少重复编写SQL语句的工作量,提高了代码的可重用性。通过使用参数化查询,可以重用同一个SQL语句的模板,只需要传入不同的参数即可。
  3. 性能优化:通过动态SQL,可以根据实时的数据情况进行优化。可以根据具体的条件生成不同的查询计划,从而提高查询性能。
  4. 维护性:动态SQL使得修改和维护SQL语句变得更加容易。当需求变化时,只需要修改生成SQL语句的代码,而不需要修改大量的静态SQL语句。

1.3.演示

根据我们自动生成的xml,接口,实体进行增加代码进行动态SQL的演示操作

自动生成的实体代码( Book )对象:

package com.junlinyi.model;
public class Book {
    private Integer bid;
    private String bname;
    private Float price;
    public Book(Integer bid, String bname, Float price) {
        this.bid = bid;
        this.bname = bname;
        this.price = price;
    }
    public Book() {
        super();
    }
    public Integer getBid() {
        return bid;
    }
    public void setBid(Integer bid) {
        this.bid = bid;
    }
    public String getBname() {
        return bname;
    }
    public void setBname(String bname) {
        this.bname = bname;
    }
    public Float getPrice() {
        return price;
    }
    public void setPrice(Float price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Book{" +
                "bid=" + bid +
                ", bname='" + bname + '\'' +
                ", price=" + price +
                '}';
    }
}

自动生成的实体接口 BookMapper:

package com.junlinyi.mapper;
import com.junlinyi.model.Book;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface BookMapper {
    int deleteByPrimaryKey(Integer bid);
    int insert(Book record);
    int insertSelective(Book record);
    Book selectByPrimaryKey(Integer bid);
    int updateByPrimaryKeySelective(Book record);
    int updateByPrimaryKey(Book record);
    //增加根据多个ID(bid)查询多个数据的方法
    List<Book> selectByBll(@Param("bids") List bids);
}

自动生成的 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.junlinyi.mapper.BookMapper" >
  <resultMap id="BaseResultMap" type="com.junlinyi.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="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from t_mvc_book
    where bid = #{bid,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from t_mvc_book
    where bid = #{bid,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.junlinyi.model.Book" >
    insert into t_mvc_book (bid, bname, price
      )
    values (#{bid,jdbcType=INTEGER}, #{bname,jdbcType=VARCHAR}, #{price,jdbcType=REAL}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.junlinyi.model.Book" >
    insert into t_mvc_book
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="bid != null" >
        bid,
      </if>
      <if test="bname != null" >
        bname,
      </if>
      <if test="price != null" >
        price,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="bid != null" >
        #{bid,jdbcType=INTEGER},
      </if>
      <if test="bname != null" >
        #{bname,jdbcType=VARCHAR},
      </if>
      <if test="price != null" >
        #{price,jdbcType=REAL},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.junlinyi.model.Book" >
    update t_mvc_book
    <set >
      <if test="bname != null" >
        bname = #{bname,jdbcType=VARCHAR},
      </if>
      <if test="price != null" >
        price = #{price,jdbcType=REAL},
      </if>
    </set>
    where bid = #{bid,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.junlinyi.model.Book" >
    update t_mvc_book
    set bname = #{bname,jdbcType=VARCHAR},
      price = #{price,jdbcType=REAL}
    where bid = #{bid,jdbcType=INTEGER}
  </update>
<!-- 根据多个bid(编号)进行查询出多个Book(对象),bids参数需要是一个List<Integer> 集合-->
  <select id="selectByBll" resultType="com.junlinyi.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>

其中的动态SQL可以根据自己的需要进行编写 :

 <select id="selectByBll" resultType="com.junlinyi.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> 

再将以下代码增加到增加编写的接口中:

//    封装方法
    List<Book> selectByBll(List bids);

然后在实现类中增加以下代码:

//    方法实现
    @Override
    public List<Book> selectByBll(List bids) {
        return bookMapper.selectByBll(bids);
    }

最后我们就可以在Demo测试类中进行方法调用测试

在Demo中增加以下代码进行测试 :  

    @Test
    public void Bll(){
        List<Integer> bids = Arrays.asList(new Integer[]{41,42,43,45,47});
             //jdk1.8的新特性写法  
      bookBiz.selectByBll(bids).forEach(System.out::println);
//上面这个等于下面这个,上面这个方便大佬们理解
//        for (Book book: bookBiz.selectByBll(bids)) {
//            System.out.println(book);
//        }
    }

结果:


二.#{...}与${...}的区别

2.1  #使用

2.1.1.#占位符语法

  • #占位符会将传入的参数值自动进行预编译处理,可以防止SQL注入攻击。
  • 使用#占位符时,Mybatis会将参数值以安全的方式替换到SQL语句中,使用JDBC的预编译语句来执行SQL查询。
  • #占位符在生成SQL语句时会对参数值进行类型处理,将参数值转换为对应的JDBC类型。
  • #占位符可以防止SQL注入攻击,但是无法实现动态拼接SQL片段。

2.1.2. #优点

#占位符语法在使用动态SQL时具有以下优点:


  • 防止SQL注入攻击:#占位符语法会将传入的参数值进行预编译处理,将参数值转换为对应的JDBC类型。这样可以防止恶意输入对SQL语句造成的安全威胁,提高了系统的安全性。
  • 参数值类型处理:#占位符语法会对参数值进行类型处理,将参数值转换为对应的JDBC类型。这样可以避免在SQL语句中手动进行类型转换的麻烦,提高了开发效率。
  • 可读性和可维护性:使用#占位符语法可以使SQL语句更加清晰和可读,因为参数值被封装在占位符中,不会直接出现在SQL语句中。这样可以方便后续的维护和修改,减少出错的可能性。
  • 兼容性:#占位符语法是Mybatis的特有语法,相对于$占位符语法更具有兼容性。如果项目需要切换到其他ORM框架,使用#占位符语法可以减少代码的修改量。

综上所述,#占位符语法具有防止SQL注入攻击、参数值类型处理、可读性和可维护性、兼容性等优点。因此,在项目中使用动态SQL时,推荐使用#占位符语法。

2.2.$使用

2.2.1. $占位符语法

  • $占位符会直接将传入的参数值替换到SQL语句中,不进行预编译处理。
  • 使用$占位符时,Mybatis会将参数值直接替换到SQL语句中,生成最终的SQL语句。
  • $占位符在生成SQL语句时不会对参数值进行类型处理,参数值会直接拼接到SQL语句中,可能存在安全风险。
  • $占位符可以实现动态拼接SQL片段,但是可能存在SQL注入攻击的风险。

2.2.2.$优点

$占位符语法在使用动态SQL时具有以下优点:


  • 动态拼接SQL片段:$占位符语法允许在SQL语句中直接使用参数值,可以方便地进行动态拼接SQL片段。这样可以在某些特殊情况下,更灵活地构建SQL语句。
  • 字段名动态替换:$占位符语法可以用于动态替换字段名。这在某些场景下非常有用,比如需要根据用户的选择动态查询不同的字段。
  • SQL语句灵活性:$占位符语法允许在SQL语句中使用任意有效的SQL表达式。这样可以在SQL语句中进行一些复杂的计算、字符串拼接等操作。

综上所述,$占位符语法在某些特殊情况下具有灵活性和动态拼接SQL的优势,但需要注意SQL注入攻击的风险,并且可能会降低SQL语句的可读性和可维护性。因此,在使用动态SQL时,#占位符语法具有防止SQL注入攻击、参数值类型处理、可读性和可维护性、兼容性等优点。因此,在项目中使用动态SQL时,推荐使用#占位符语法。只有在特殊情况下,需要动态拼接SQL片段或动态替换字段名时,才考虑使用占位符语法,并且需要确保参数值的安全性。

2.3.案例演示

下面是一个案例演示,展示了$符号和#符号的区别:

<select id="getBooksByPrice" parameterType="Map" resultMap="BaseResultMap">
  SELECT * FROM books
  WHERE price > ${minPrice} AND price < #{maxPrice}
</select>

在这个示例中,getBooksByPrice是一个查询操作,根据传入的minPrice和maxPrice参数来查询价格在指定范围内的书籍。

  • 如果使用$符号占位符,例如传入minPrice=10和maxPrice=20,生成的SQL语句为:
  SELECT * FROM books
  WHERE price > 10 AND price < 20

注意,$符号占位符直接将参数的值替换到SQL语句中,不进行预编译和参数类型处理。

  • 如果使用#符号占位符,例如传入minPrice=10和maxPrice=20,生成的SQL语句为:
  SELECT * FROM books
  WHERE price > ? AND price < ?

注意,#符号占位符将参数值作为预编译参数传递给数据库,可以防止SQL注入攻击。


小提示:表名作为变量时,必须使用 ${ }

这是因为,表名是字符串,使用 sql 占位符替换字符串时会带上单引号 '',这会导致 sql 语法错误,例如:

select * from #{tableName} where name = #{name};

预编译之后的sql 变为:

select * from ? where name = ?;

假设我们传入的参数为 tableName = "books" , name = "ycxw",那么在占位符进行变量替换后,sql 语句变为:

select * from 'books' where name='junlinyi';

上述 sql 语句是存在语法错误的,表名不能加单引号 ''(注意: 反引号 ``是可以的)

三.resultMap和resultType的区别

区别:

  • resultType用于简单的结果映射,适用于查询结果列与Java对象属性名一致的情况,自动进行映射。
  • resultMap用于复杂的结果映射,适用于查询结果列与Java对象属性名不一致或需要自定义映射关系的情况,需要手动定义映射关系。

esultType适用于简单的结果映射,可以自动进行映射;


resultMap适用于复杂的结果映射,需要手动定义映射关系。


根据具体的需求和情况,选择合适的配置项来实现查询结果的映射。

  好啦,今天的分享就到这了,希望能够帮到你呢!😊😊  

目录
相关文章
|
6月前
|
SQL Java 数据库连接
【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号";"报错
【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号";"报错
|
5月前
|
SQL Java 数据库连接
MyBatis动态SQL字符串空值判断,这个细节99%的程序员都踩过坑!
本文深入探讨了MyBatis动态SQL中字符串参数判空的常见问题。通过具体案例分析,对比了`name != null and name != &#39;&#39;`与`name != null and name != &#39; &#39;`两种写法的差异,指出后者可能引发逻辑混乱。为避免此类问题,建议在后端对参数进行预处理(如trim去空格),简化MyBatis判断逻辑,提升代码健壮性与可维护性。细节决定成败,严谨处理参数判空是写出高质量代码的关键。
597 0
|
4月前
|
SQL XML Java
菜鸟之路Day35一一Mybatis之XML映射与动态SQL
本文介绍了MyBatis框架中XML映射与动态SQL的使用方法,作者通过实例详细解析了XML映射文件的配置规范,包括namespace、id和resultType的设置。文章还对比了注解与XML映射的优缺点,强调复杂SQL更适合XML方式。在动态SQL部分,重点讲解了`&lt;if&gt;`、`&lt;where&gt;`、`&lt;set&gt;`、`&lt;foreach&gt;`等标签的应用场景,如条件查询、动态更新和批量删除,并通过代码示例展示了其灵活性与实用性。最后,通过`&lt;sql&gt;`和`&lt;include&gt;`实现代码复用,优化维护效率。
281 5
|
6月前
|
SQL Java 数据库连接
【YashanDB 知识库】解决 mybatis 的 mapper 文件 sql 语句结尾加分号";"报错
【YashanDB 知识库】解决 mybatis 的 mapper 文件 sql 语句结尾加分号";"报错
|
6月前
|
SQL 缓存 Java
框架源码私享笔记(02)Mybatis核心框架原理 | 一条SQL透析核心组件功能特性
本文详细解构了MyBatis的工作机制,包括解析配置、创建连接、执行SQL、结果封装和关闭连接等步骤。文章还介绍了MyBatis的五大核心功能特性:支持动态SQL、缓存机制(一级和二级缓存)、插件扩展、延迟加载和SQL注解,帮助读者深入了解其高效灵活的设计理念。
|
6月前
|
SQL XML Java
七、MyBatis自定义映射resultMap
七、MyBatis自定义映射resultMap
151 6
|
6月前
|
Java 数据库连接 mybatis
MyBatis篇-映射关系(1-1 1-n n-n)
本文介绍了MyBatis中四种常见关系映射的配置方法,包括一对一、一对多、多对一和多对多。**一对一**通过`resultMap`实现属性与字段的映射;**一对多**以用户-角色为例,使用`&lt;collection&gt;`标签关联集合数据;**多对一**以作者-博客为例,利用`&lt;association&gt;`实现关联;**多对多**则通过引入第三方类(如UserForDept)分别在User和Dept类中添加集合属性,并配置对应的`&lt;collection&gt;`标签完成映射。这些方法解决了复杂数据关系的处理问题,提升了开发效率。
|
6月前
|
SQL XML Java
六、MyBatis特殊的SQL:模糊查询、动态设置表名、校验名称唯一性
六、MyBatis特殊的SQL:模糊查询、动态设置表名、校验名称唯一性
148 0
|
12月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
407 13