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


    Mybatis学习目录

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

    环境

    数据库:汽车表t_car、t_log_20220901
    Mybatis工具类
    引入依赖:mysql驱动依赖、mybatis依赖、logback依赖、junit依赖。
    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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    #{}与${}的区别

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

    使用#{}

    创建一个CarMapper接口

    public interface CarMapper {
        /**
         * 通过汽车类型查询
         * @param carType
         * @return
         */
        List<Car> selectByCarType(String carType);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    创建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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试程序

    	@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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    请添加图片描述

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

    使用${}

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

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

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

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

    <!--where car_type = #{carType}-->
    <!--where car_type = ${carType}-->
    	where car_type = '${carType}'
    
    • 1
    • 2
    • 3

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

    情况一:升序与降序

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

    CarMapper接口中新增一个方法

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

    先#{}进行测试
    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试程序

    	@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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行发现出现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'
    
    • 1

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    创建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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试程序:

    	@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);
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行请添加图片描述

    情况三:批量删除

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

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

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

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

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

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

    在CarMapper接口中新增一个方法

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

    在CarMapper.xml进行配置

    	<delete id="deleteBatch">
            delete
            from t_car
            where id in(${ids});
        </delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试程序

    	@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);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果:
    请添加图片描述

    情况四:模糊查询

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

    ‘%${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>
    
    • 1
    • 2
    • 3

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

    <typeAlias type="com.antis.pojo.Car" alias="iii" />
            <package name="com.antis.pojo"/>
    </typeAliases>
    
    • 1
    • 2
    • 3
  • 相关阅读:
    随机森林算法深入浅出
    视频转文字怎么操作?这三种转换方法你该学会
    Excel如何快速将表格纵向数据变成横向
    如何快速安装JDK 1.8 以及配置环境变量
    基于SSH开发校园社团管理系统 课程设计 大作业 毕业设计
    P6775 [NOI2020] 制作菜品
    SpringMVC前后端分离交互传参详细教程
    SparkStreaming消费kafka存储到Elasticsearch
    Hystrix 部署
    Ui自动化测试如何上传文件
  • 原文地址:https://blog.csdn.net/weixin_45832694/article/details/127652255