当前位置: 首页 > news >正文

(七)Mybatis传值中#{}和${}的区别,及别名机制

文章目录

  • 环境
  • #{}与${}的区别
    • 使用#{}
    • 使用${}
      • 情况一:升序与降序
      • 情况二:拼接表名
      • 情况三:批量删除
      • 情况四:模糊查询
  • 别名机制

上一篇:(六)Mybatis中接口代理机制及使用
下一篇:(八)MyBatis中参数的处理

环境

数据库:汽车表t_car、t_log_20220901
Mybatis工具类
依赖
mybatis-config.xml、logback.xml
pojo类:Car、Log
除了t_log_20220901、Log,其他可以去复制之前的
t_log_20220901:

  • id 主键(自增)[int]
  • log 日志信息 [varchar]
  • time 日志时间 [varchar]

请添加图片描述
Log类

package com.antis.pojo;

public class Log {
    private Integer id;
    private String log;
    private String time;

    public Log() {
    }

    public Log(Integer id, String log, String time) {
        this.id = id;
        this.log = log;
        this.time = time;
    }

    @Override
    public String toString() {
        return "Log{" +
                "id=" + id +
                ", log='" + log + '\'' +
                ", time='" + time + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLog() {
        return log;
    }

    public void setLog(String log) {
        this.log = log;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

#{}与${}的区别

在Mybatis的sql语句传值中,除了能够用#{}进行传值之外,还可以使用${}进行传值,它们的区别是:
#{}:先编译sql语句,再给占位符传值,底层是PreparedStatement实现。可以防止sql注入,比较常用。
${}:先进行sql语句拼接,然后再编译sql语句,底层是Statement实现。存在sql注入现象。只有在需要进行sql语句关键字拼接的情况下才会用到。

使用#{}

创建一个CarMapper接口

public interface CarMapper {
    /**
     * 通过汽车类型查询
     * @param carType
     * @return
     */
    List<Car> selectByCarType(String carType);
}

创建CarMapper.xml映射文件放在类路径下,注意namespace是接口的全限定类名,id是接口的方法名

<?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.antis.mapper.CarMapper">
	<select id="selectByCarType" resultType="com.antis.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>

测试程序

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

请添加图片描述

执行之后可以清楚的看到,sql语句中是带有 ‘?’ 的,这个 ‘?’ 就是占位符,专门用来接收值的。会把‘燃油车’这个字符串类型传给 ‘?’。
这就是 #{},它会先进行sql语句的预编译,然后再给占位符传值

使用${}

还是上面的程序,我们在CarMapper映射文件里把#替换成$试试

<!--where car_type = #{carType}-->
 where car_type = ${carType}

运行测试程序会出现错误,因为${}是先进行字符串拼接,再进行编译,出现语法错误是正常的,因为 ‘燃油车’ 是⼀个字符串,在sql语句中应该添加单引号

请添加图片描述
在CarMapper映射文件修改如下:

<!--where car_type = #{carType}-->
<!--where car_type = ${carType}-->
	where car_type = '${carType}'

再次运行,我们发现它真的是把字符串拼接到sql语句里面
请添加图片描述
一般来说,不是特殊的需求,一般都用#{},而不会用${}
当需要进行sql语句关键字拼接的时候,必须使用${}

情况一:升序与降序

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

CarMapper接口中新增一个方法

	/**
     * 查询所有的信息,通过asc或desc进行升序和降序
     * @param ascOrDesc
     * @return
     */
    List<Car> selectAllByAscOrDesc(String ascOrDesc);

先#{}进行测试
CarMapper.xml文件:

<select id="selectAllByAscOrDesc" resultType="com.antis.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
                produce_time #{ascOrDesc}
</select>

测试程序

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

运行发现出现sql语句异常,原因是sql语句不合法,因为采用这种方式传值,最终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 'asc'

asc是关键字,不应该是一个字符串,所以只能用KaTeX parse error: Expected 'EOF', got '#' at position 22: …rMapper.xml文件中把#̲该为
再次运行,成功排序
请添加图片描述
请添加图片描述

情况二:拼接表名

业务背景:实际开发中,有的表数据量非常庞大,可能会采用分表方式进行存储,比如每天生成一张表,表的名字与日期挂钩,例如: 2022年8月1日生成的表: t _user20220108. 2000年1 月1日生成的表: t _user20000101。此时前端在进行查询的时候会提交一个具体的日期, 比如前端提交的日期为:2000年1月1日,那么后端就会根据这个日期动态拼接表名为: t _user20000101。有了这个表名之后,将表名拼接到sq|语句当中,返回查询结果。那么大家思考-下,拼接表名到sq|语句当中应该使用#0}还是${}呢?

使用#{}会是这样:select * from ‘t_userXXX’
使用${}会是这样:select * from t_usrXXX

表名不应该是一个字符串,所以只能使用${}

创建一个LogMapper接口中添加一个方法:

public interface LogMapper {
    /**
     * 根据日期查询不同的表,获取表所有信息
     * @param date
     * @return
     */
    List<Log> selectAllByTable(String date);
}

创建LogMapper.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.antis.mapper.LogMapper">
    <select id="selectAllByTable" resultType="com.antis.pojo.Log">
        select *
        from t_log_${date};
    </select>
</mapper>

测试程序:

	@Test
    public void testSelectAllByTable(){
        SqlSession session = SqlSessionUtil.getSession();
        LogMapper mapper = session.getMapper(LogMapper.class);
        List<Log> logs = mapper.selectAllByTable("20220901");
        logs.forEach(log -> {
            System.out.println(log);
        });
    }

运行请添加图片描述

情况三:批量删除

业务背景:用户想要删除信息的使用,勾选多个信息,进行批量删除

批量删除的SQL语句有两种写法:

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

假设现在使用in的方式处理,前端传过来的字符串:1, 2, 3
使用#{} :

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

会出现语法错误,因为in里面不是一个字符串类型
所以只能使用${}

在CarMapper接口中新增一个方法

/**
     * 批量删除,根据id
     * @param ids 传一个字符串id,用','隔开
     * @return
     */
    int deleteBatch(String ids);

在CarMapper.xml进行配置

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

测试程序

	@Test
    public void testDeleteBatch(){
        SqlSession session = SqlSessionUtil.getSession();
        CarMapper mapper = session.getMapper(CarMapper.class);
        int i = mapper.deleteBatch("16,17");
        System.out.println(i);
        session.commit();
        SqlSessionUtil.close(session);
    }

结果:
请添加图片描述

情况四:模糊查询

需求:通过汽车品牌模糊查询。
第一种方案:

‘%${brand}%’

第二种方案:concat函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接

concat(‘%’,#{brand},‘%’)

第三种方案:比较鸡肋了。可以不算。

concat(‘%’,‘${brand}’,‘%’)

第四种方案:

“%”#{brand}“%”

别名机制

起别名标签:typeAlias

  • type:被指定的别名

  • alias:指定别名,可以省略,省略后别名默认是类的简称,例如com.antis.pojo.Car就是car(不区分大小写)

到时候在映射文件中的resultType就可以使用这个别名,别名不区分大小写

<typeAlias type="com.antis.pojo.Car" alias="iii" />
        <typeAlias type="com.antis.pojo.Car" alias="iii" />
</typeAliases>

自动通过包起别名标签:package
自动把name这个包下的所有类自动起别名,是类的简称,不区分大小写。

<typeAlias type="com.antis.pojo.Car" alias="iii" />
        <package name="com.antis.pojo"/>
</typeAliases>

相关文章:

  • 网站开发的功能需求文档/seo优化排名怎么做
  • 网站功能架构图怎么做/站长工具如何使用
  • 网站建设协议/免费网站外链推广
  • 做网站选哪家/百度一下 你就知道官网
  • wordpress的多说美化/站长交流平台
  • 义乌网站建设成都网站设计/营销网站建设价格
  • 云原生之快速使用Nacos Spring Cloud
  • 【Vue】vue-router的基本使用 | 路由懒加载 | 补充知识点
  • 装了我这 10 个 IDEA 神级插件后,同事也开始情不自禁的嘚瑟了
  • java-php-python-火炬中学校刊在线投稿审稿系统计算机毕业设计
  • Qt中中文处理-编码格式转换
  • 《设计模式:可复用面向对象软件的基础》——行为模式(3)(笔记)
  • Spring Bean 的生命周期(看着图不迷路)
  • 自动化早已不是那个自动化了,谈一谈自动化测试现状和自我感受……
  • 公众号网课搜题接口-单独后台控制
  • MySQL 优化,查询的原理,索引的使用,如何优化查询
  • C++ 基础知识 ∈ C++ 编程笔记
  • 【微服务】基于Ribbon实现负载均衡