总结:

#{}:先编译sql语句,再给占位符传值,底层是PreparedStatement实现。可以防止sql注入,比较常用。

${}:先进行sql语句拼接,然后再编译sql语句,底层是Statement实现。存在sql注入现象。只有在需要进行sql语句关键字拼接的情况下才会用到。

#{}的使用场景:

#{} 的工作机制:

MyBatis 会将 #{} 中的参数替换为 SQL 预编译语句 的占位符(即 ?),然后将参数通过 JDBC 预编译的方式传递给数据库。

Mapper 接口

public interface CarMapper {
    List<Car> selectByCarType(String carType);
}

XML 配置

<select id="selectByCarType" resultType="com.powernode.mybatis.pojo.Car">
    select
        id, car_num as carNum, brand, guide_price as guidePrice, 
        produce_time as produceTime, car_type as carType
    from
        t_car
    where
        car_type = #{carType}
</select>

Service 层调用

List<Car> cars = carMapper.selectByCarType("SUV");

在这里,"SUV" 这个参数会通过 MyBatis 的 #{} 绑定机制,替换到 SQL 语句中的占位符 ? 处,然后执行查询。

MyBatis 转换后的 SQL:

在 MyBatis 运行过程中,这段 SQL 会被转换成如下形式:

select
    id, car_num as carNum, brand, guide_price as guidePrice, 
    produce_time as produceTime, car_type as carType
from
    t_car
where
    car_type = ?

实际执行过程:

假设用户调用了如下 Java 代码:

List<Car> cars = carMapper.selectByCarType("SUV");

在实际执行时,JDBC 会生成如下的最终 SQL 语句,并将 "SUV" 参数绑定到 ? 占位符:

select
    id, car_num as carNum, brand, guide_price as guidePrice, 
    produce_time as produceTime, car_type as carType
from
    t_car
where
    car_type = 'SUV';

${}:

${} 的使用和 #{} 不同,它是直接拼接参数到 SQL 语句中,而不是作为 JDBC 预编译的占位符。因此,${} 具有一定的风险(SQL 注入),但在某些场景下它仍然是有用的。

1. ${} 的工作原理

  • ${} 会将参数的值直接拼接到 SQL 语句中,在 SQL 执行前完成字符串替换。
  • 它不经过预编译,因此无法避免 SQL 注入风险。
  • 示例:使用 ${} 拼接参数

    <select id="selectByCarType" resultType="com.powernode.mybatis.pojo.Car">
        select
            id, car_num as carNum, brand, guide_price as guidePrice, 
            produce_time as produceTime, car_type as carType
        from
            t_car
        where
            car_type = ${carType}
    </select>
    

    如果 Java 代码中传入参数为 "SUV"

    carMapper.selectByCarType("SUV");
    

    执行的 SQL 语句会被拼接成:

    select
        id, car_num as carNum, brand, guide_price as guidePrice, 
        produce_time as produceTime, car_type as carType
    from
        t_car
    where
        car_type = SUV;
    

    这条 SQL 会出错,因为它缺少引号来包裹字符串类型的值。根据 SQL 规范,在 SQL 语句中,字符串类型的值(如 "SUV")必须用 单引号 ' 包裹起来,否则会报语法错误。

    如何解决报错?

    加上单引号即可

    <?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.powernode.mybatis.mapper.CarMapper">
        <select id="selectByCarType" resultType="com.powernode.mybatis.pojo.Car">
            select
                id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
            from
                t_car
            where
                <!--car_type = #{carType}-->
                <!--car_type = ${carType}-->
                car_type = '${carType}'
        </select>
    </mapper>

    ${} 的适用场景 :

    需求:通过向sql语句中注入asc或desc关键字,来完成数据的升序或降序排列。

    CarMapper接口:

    List<Car> selectAll(String ascOrDesc);

    CarMapper.xml文件:

    <select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
      select
      id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
      from
      t_car
      order by carNum #{key}
    </select>

    测试程序 

    @Test
    public void testSelectAll(){
        CarMapper mapper = (CarMapper) SqlSessionUtil.openSession().getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAll("desc");
        cars.forEach(car -> System.out.println(car));
    }

    采用这种方式传值,最终sql语句会是这样:

    select 
        id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType 
    from t_car order by carNum 'desc'

     desc是一个关键字,不能带单引号的,所以在进行sql语句关键字拼接的时候,必须使用${}!!

    使用${} 改造  :

    <select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
      select
      id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
      from
      t_car
      <!--order by carNum #{key}-->
      order by carNum ${key}
    </select>

    批量删除

    需求:一次删除多条记录。

    对应的sql语句:

  • delete from t_user where id = 1 or id = 2 or id = 3;

  • delete from t_user where id in(1, 2, 3);

  •  我们到底需要选择#{}还是${}呢?

    正确选择应该是${},因为选择#{},sql语句会变成delete from t_user where id in('1,2,3')  执行错误:1292 – Truncated incorrect DOUBLE value: '1,2,3'

    正确写法:

    <delete id="deleteBatch">
      delete from t_car where id in(${ids})
    </delete>

    对应的接口:

    /**
         * 根据id批量删除
         * @param ids
         * @return
         */
    int deleteBatch(String ids);

    模糊查询:

    查询奔驰系列的汽车。【只要品牌brand中含有奔驰两个字的都查询出来。】

    使用${}

    /**
         * 根据品牌进行模糊查询
         * @param likeBrank
         * @return
         */
    List<Car> selectLikeByBrand(String likeBrank);
    <select id="selectLikeByBrand" resultType="Car">
      select
      id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
      from
      t_car
      where
      brand like '%${brand}%'
    </select>

    对应的sql语句:

      select
      id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
      from
      t_car
      where
      brand like '%宝马%'
    @Test
    public void testSelectLikeByBrand(){
        CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
        List<Car> cars = mapper.selectLikeByBrand("奔驰");
        cars.forEach(car -> System.out.println(car));
    }

    使用#{}

    第一种:concat函数
    ​
    <select id="selectLikeByBrand" resultType="Car">
      select
      id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
      from
      t_car
      where
      brand like concat('%',#{brand},'%')
    </select>
    
    ​
    第二种:双引号方式(比较常用)
    <select id="selectLikeByBrand" resultType="Car">
      select
      id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
      from
      t_car
      where
      brand like "%"#{brand}"%"
    </select>

    作者:代码代码快快显灵

    物联沃分享整理
    物联沃-IOTWORD物联网 » #{}和${}

    发表回复