03-MyBatis中动态的给SQL语句赋值方式,详解占位符${}和#{}的区别和应用场景

动态的给SQL语句赋值方式

实际开发中SQL语句的参数值是不能写死到配置文件中的,应该由前端发起的请求中包含的请求参数中的数据决定

<insert id="insertCar">
    insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
    values(null,'1003','丰田霸道',30.0,'2000-10-11','燃油车');
</insert>

JDBC当中的占位符

在JDBC中使⽤?作为占位符,在程序的执行过程中,我们需要手动给SQL语句中的占位符传值

String sql = "insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)";
ps = conn.prepareStatement(sql);
// 给?传值
ps.setString(1,"103");
ps.setString(2,"奔驰E300L");
ps.setDouble(3,50.3);
ps.setString(4,"2022-01-01");
ps.setString(5,"燃油⻋");
// 执行SQL语句
int count = ps.executeUpdate();

MyBatis中的占位符

#{}底层使用的是PreparedStatement对象:SQL语句中含有占位符,先对SQL语句进行预编译,然后获取值给SQL语句中的占位符 ? 传值, 可以避免SQL注入的风险

  • 占位符?传值的时候会原封不动地把值传过去(包括值的引号),即使用户提供的信息中含有sql语句关键字也无法参与编译过程,最终被当作普通的字符处理

${}底层使用的是Statement对象: 直接将获取的值拼接到SQL语句当中,然后对拼接好的SQL语句进行编译,这样做存在SQL注入的风险

  • 将动态传入的值拼接到SQL语句中后参数得引号就没有了,此时的参数值和SQL是一个整体

对于#{}(可以避免SQL注入的风险)${}(可以进⾏SQL语句关键字拼接)底层都会根据条件自动获取对应的值然后为占位符赋值,最后将获取到值传给SQL语句

<insert id="insertCar">
    insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) 
    values(null,#{carNum},#{brand},#{guidePrice},{produceTime},#{carType});
</insert>

${}的应用

数据的升序或降序

需求:通过向SQL语句中注⼊asc或desc关键字来完成查询数据的升序或降序排列

public interface CarMapper {
    
    
    // 查询所有的汽车信息
    List<Car> selectAllByAscOrDesc(String ascOrDesc);
}

public class CarMapperTest {
    
    
    @Test
    public void testSelectAllByAscOrDesc(){
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAllByAscOrDesc("desc");
        cars.forEach(car -> System.out.println(car));
        sqlSession.close();
    }
}

使用#{}会将获取到的SQL关键字(含引号)赋值给占位符?,这样会报SQL语法错误

<select id="selectAllByAscOrDesc" resultType="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 
    	<!--拼接后的SQL:produce_time "desc"-->
    	produce_time #{ascOrDesc}
</select>  

**使用${}可以将获取到的SQL关键字直接拼接到SQL语句当中完成数据的升序或降序 **

<select id="selectAllByAscOrDesc" resultType="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
    	<!--拼接后的SQL:produce_time desc-->
        produce_time ${ascOrDesc}
</select>  

拼接表名

实际开发中表的数据量非常庞大,如果将所有数据都存在一张表中的话会导致表的查询效率比较低(扫描的数据量太大),所以需要将这些数据有规律的分表存储

日志表是专门用来存储日志信息的表,如果只有一张日志表,随着每天日志的增加表中的数据会越来越多,所以需要每天生成一个日志表如以当天日期作为表名称

需求: 前端在进行查询的时候会提交⼀个具体的⽇期,后端根据这个日期动态拼接得到一个表名,最后将这个表名拼接到SQL语句中查询表中的数据

public class Log {
    
    
    private Integer id;
    private String log;
    private String time;
    //setter和getter方法
    @Override
    public String toString() {
    
    
        return "Log{" +
                "id=" + id +
                ", log='" + log + '\'' +
                ", time='" + time + '\'' +
                '}';
    }
}
public interface LogMapper {
    
    
   // 根据日期名查询不同的表,获取表中所有的日志
   List<Log> selectAllByTable(String date);
}
public class LogMapperTest {
    
    
    @Test
    public void testSelectAllByTable(){
    
    
        SqlSession sqlSession = SqlSessionUtil.openSession();
        LogMapper mapper = sqlSession.getMapper(LogMapper.class);
        List<Log> logs = mapper.selectAllByTable("20220901");
        logs.forEach(log -> System.out.println(log));
    }
}

使用#{}的方式会将获取到的表名(含引号)赋值给占位符?,这样会报SQL语法错误

<mapper namespace="com.powernode.mybatis.mapper.LogMapper">
    <select id="selectAllByTable" resultType="Log">
        <!--select * from t_log_'20220901'-->
        select * from t_log_#{date}
    </select>
</mapper>

使用${}的方式将获取到的表名直接拼接到SQL语句之后

<!--namespace不能使用别名机制,必须写带有包名的全限定接口名称-->
<mapper namespace="com.powernode.mybatis.mapper.LogMapper">
    <select id="selectAllByTable" resultType="Log">
        <!--select * from t_log_20220901-->
        select * from t_log_${date}
    </select>
</mapper>

批量删除(in的方式)

批量删除时可以使用orin

  • or:delete from t_car where id=1 or id=2 or id=3;
  • in:delete from t_car where id in(1,2,3);

需求: 使用in关键字批量删除多条记录

public interface CarMapper {
    
    
    //根据id批量删除
	int deleteBatch(String ids);  
}

@Test
public void testDeleteBatch(){
    
    
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    int count = mapper.deleteBatch("1,2,3");
    System.out.println("删除了⼏条记录:" + count);
    SqlSessionUtil.openSession().commit();
}

使用#{}的方式会将获取到的所有Id(含引号)赋值给占位符?,这样会报SQL语法错误

<delete id="deleteBatch">
    <!--delete from t_user where id in('1,2,3')-->
    delete from t_car where id in(#{ids})
</delete>

使用${}的方式将获取到的所有Id直接拼接到SQL语句之后

<delete id="deleteBatch">
    <!--delete from t_user where id in(1, 2, 3)  -->
    delete from t_car where id in(${ids})
</delete>

猜你喜欢

转载自blog.csdn.net/qq_57005976/article/details/134773483
今日推荐