SpringBoot + Mybatis系列之传参作为字段/表名时的注意事项

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 今天遇到一个非常有意思的事情,一个小伙伴反馈,同样的 sql,为啥直接通过 mysql 终端执行的结果,和 mybatis 的执行结果不一致,感觉有点鬼畜;然后看了一下,发现这是个比较典型的问题,#{}与${}的使用区别接下来我们看一下这个问题,顺带也重新学习一下它们两的区别

image.png


今天遇到一个非常有意思的事情,一个小伙伴反馈,同样的 sql,为啥直接通过 mysql 终端执行的结果,和 mybatis 的执行结果不一致,感觉有点鬼畜;然后看了一下,发现这是个比较典型的问题,#{}${}的使用区别


接下来我们看一下这个问题,顺带也重新学习一下它们两的区别


I. 环境配置



我们使用 SpringBoot + Mybatis + MySql 来搭建实例 demo


  • springboot: 2.2.0.RELEASE
  • mysql: 5.7.22


1. 项目配置


<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>
复制代码


核心的依赖mybatis-spring-boot-starter,至于版本选择,到 mvn 仓库中,找最新的


另外一个不可获取的就是 db 配置信息,appliaction.yml


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
复制代码


2. 数据库表


用于测试的数据库


CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT '钱',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;
复制代码


II. 场景复现



一个简单的 demo 来演示下使用姿势,根据传参,来指定排序的字段;


List<MoneyPo> orderBy(@Param("order") String order);
复制代码


对应的 xml 如下

<select id="orderBy" resultMap="BaseResultMap">
    select * from `money` order by #{order} asc
</select>
复制代码


上面这个执行之后可能与我们预期的不一致,如下


image.png


1. 问题修复


上面的演示中,本来是希望根据传参进行排序,最后的执行结果会发现都是按照 id 进行排序


要解决上面这个问题,也很简单,将#改成$

<select id="orderBy" resultMap="BaseResultMap">
    select * from `money` order by ${order} asc
</select>
复制代码


再次测试如下,和我们的预期一致了

image.png


2. 原因分析


上面这个问题的关键原因在于 $#的本质区别,有过一点了解的小伙伴会知道$最终的效果是替换,而#则是占位


比如上面的两个,转成 sql,对应如下


  • #{}: select * from money order by 'money' asc
  • 注意 money 作为字符串传入的
  • ${}: select * from money order by money asc
  • 注意 money 作为列名


上面的第一个 sql,非常有意思,执行居然不会抛错,可以正常执行(注意,这个与数据库版本有关,并不是所有的版本都可以正常执行)


image.png


3. #{}与${}对比


#{} ${}
参数占位,相当于 ? 直接替换到 sql 的一部分
动态解析 -> 预编译 -> 执行 动态解析 -> 编译 -> 执行
变量替换是在 DBMS 中 变量替换是在 DBMS 外
变量替换后,#{} 对应的变量自动加上单引号 '' 变量替换后,${} 对应的变量不会加上单引号 ''
防 sql 注入 不能防 sql 注入


注意事项:

select * from money where name = #{name}
select * from money where name = ${name}
复制代码


如上面两条 sql,在具体传参的时候,就会有一个显著的去呗

  • #{name}: 传参 一灰灰,对应 sql 如下
  • select * from money where name = '一灰灰'
  • ${name}: 传参 一灰灰,对应 sql 如下
  • select * from money where name = 一灰灰
  • 注意上面的 sql 中,name 的传参没有引号,直接就是 bad sql
  • 所以传参应该是 '一灰灰',需要手动的加上单引号


使用姿势:

  • 能用 #{} 的地方就用 #{},不用或少用 ${}
  • 表名作参数时,必须用 ${}
  • order by 时,必须用 ${}
  • 使用 时,要注意何时加或不加单引号,即{} 时,要注意何时加或不加单引号,即 {} 和 '${}'



相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
10月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
539 0
|
7月前
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
1260 1
Spring boot 使用mybatis generator 自动生成代码插件
|
7月前
|
SQL Java 数据库
解决Java Spring Boot应用中MyBatis-Plus查询问题的策略。
保持技能更新是侦探的重要素质。定期回顾最佳实践和新技术。比如,定期查看MyBatis-Plus的更新和社区的最佳做法,这样才能不断提升查询效率和性能。
302 1
|
10月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于注解的整合
本文介绍了Spring Boot集成MyBatis的两种方式:基于XML和注解的形式。重点讲解了注解方式,包括@Select、@Insert、@Update、@Delete等常用注解的使用方法,以及多参数时@Param注解的应用。同时,针对字段映射不一致的问题,提供了@Results和@ResultMap的解决方案。文章还提到实际项目中常结合XML与注解的优点,灵活使用两者以提高开发效率,并附带课程源码供下载学习。
798 0
|
10月前
|
Java 数据库连接 数据库
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——MyBatis 介绍和配置
本文介绍了Spring Boot集成MyBatis的方法,重点讲解基于注解的方式。首先简述MyBatis作为持久层框架的特点,接着说明集成时的依赖导入,包括`mybatis-spring-boot-starter`和MySQL连接器。随后详细展示了`properties.yml`配置文件的内容,涵盖数据库连接、驼峰命名规范及Mapper文件路径等关键设置,帮助开发者快速上手Spring Boot与MyBatis的整合开发。
1453 0
|
10月前
|
SQL XML Java
六、MyBatis特殊的SQL:模糊查询、动态设置表名、校验名称唯一性
六、MyBatis特殊的SQL:模糊查询、动态设置表名、校验名称唯一性
292 0
|
12月前
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
584 2
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
615 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
280 8