06MyBatis技巧(#{}和${}/)

1#{}和${}

  • #{}:先编译sql语句,再给占位符传值,底层是PreparedStatement实现。可以防止sql注入,比较常用。
  • ${}:先进行sql语句拼接,然后再编译sql语句,底层是Statement实现。存在sql注入现象。只有在需要进行sql语句关键字拼接的情况下才会用到。
  • 二者的区别具体表现在,#最终会化为一个占位符?, 要传的值会带着Java类型传入。
    而$不会化为任何东西,传入的东西不会带有任何Java类型,

CarMapper.xml,放在类的根路径下:注意namespace必须和接口名一致。id必须和接口中方法名一致。


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.sunsplanter.mybatis.mapper.CarMapper">
    <select id="selectByCarType" resultType="com.sunsplanter.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>
mapper>
public class CarMapperTest {

    @Test
    public void testSelectByCarType(){
        CarMapper mapper = (CarMapper) SqlSessionUtil.openSession().getMapper(CarMapper.class);
        List<Car> cars = mapper.selectByCarType("燃油车");
        cars.forEach(car -> System.out.println(car));
    }

06MyBatis技巧(#{}和${}/)_第1张图片通过执行可以清楚的看到,sql语句中是带有 ? 的,这个 ? 就是大家在JDBC中所学的占位符,专门用来接收值的。
把“燃油车”以String类型的值,传递给 ? 。(即带着Java类型传入,形成carType = ‘燃油车’)

但是,若mapper文件中改为${}:

<mapper namespace="com.sunsplanter.mybatis.mapper.CarMapper">
    <select id="selectByCarType" resultType="com.sunsplanter.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>
mapper>

则会报错,根本原因是看生成的SQL语句就知道了:在这里插入图片描述$不生成任何东西,因此传入的东西也不带有Java类型, 系统当然也不会帮助生成单引号,因此此时形成carType = 燃油车,根本就不符合语法
解决办法

  • #{}使燃油车具备Java属性String,使得系统可以自动添加单引号成为 ‘燃油车’ 后传入。
  • 继续使用${},但自己提前添加好单引号:
car_type = '${carType}'

2 必须使用${}的情况

2.1 进行SQL语句关键字拼接时,必须使用${}

需求:查询所有汽车的条目,并通过向sql语句中注入asc或desc关键字,来完成数据的升序或降序排列。

<select id="selectAll" resultType="com.sunsplanter.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));
}

如上所述,带着Java类型传入,形成语句 order by carNum ‘desc’ , 那么当然错误,关键不能用单引号括起来.

改为:

 order by carNum ${key}

此时, 传入的desc不带有Java类型,不自动生成单引号,形成order by carNum desc ,正确

2.2 批量删除,必须使用${}

需求:批量删除id为1,2,3的条目
从所需SQL语句倒推:

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

因此mapper中应为:

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

测试程序为:

@Test
public void testDeleteBatch(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    int count = mapper.deleteBatch("1,2,3");
    }

用美元符号${},将1,2,3直接放进去,而非生成单引号(where id in(‘1,2,3’))

2.3 模糊查询, 必须使用${}

需求:查询奔驰系列的汽车。【只要品牌brand中含有奔驰两个字的都查询出来。】
从所需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 '%奔驰%'

则mapper.xml为:

brand like '%${brand}%'

测试程序为:

List<Car> cars = mapper.selectLikeByBrand("奔驰");

即不带Java类型,直接把奔驰两字替代${brand}.

2.4 拼接表名,必须用${}

业务背景:实际开发中,有的表数据量非常庞大,可能会采用分表方式进行存储,比如每天生成一张表,表的名字与日期挂钩,例如:2022年8月1日生成的表:t_user20220108。2000年1月1日生成的表:t_user20000101。此时前端在进行查询的时候会提交一个具体的日期,比如前端提交的日期为:2000年1月1日,那么后端就会根据这个日期动态拼接表名为:t_user20000101。有了这个表名之后,将表名拼接到sql语句当中,返回查询结果。

需求:向SQL语句中注入表名,完成查询特定表

<select id="selectAllByTableName" resultType="car">
  select
  id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
  from
  ${tableName}
select>

对应接口CarMapper中有方法:

List<Car> selectAllByTableName(String tableName)

测试程序为:

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

表名也是关键字,不应被单引号括起,因此应用美元符号${}, 形成from t_car

你可能感兴趣的:(Mybatis,mybatis)