MyBatis—操作数据库(三)

简介: MyBatis—操作数据库(三)

在 xml 中实现方法


<delete id="delUserInfo">
    delete from userinfo where id = #{id};
</delete>

单元测试验证效果


不污染数据库进行单元测试


利用注解@Transactional

注解@Transactional既可以修饰类, 也可以修饰方法


举个栗子🌰

要求

测试删除功能是否正常 + 数据库中的数据不会被删除

(即不污染数据库进行单元测试)

此时可以利用注解@Transactional

删除功能正常🍂

数据库中的数据不会被删除🍂

🔎对比 # 与 $


根据 id 查询用户信息


/**
* 根据 Id 查询用户信息
* @author bibubibu
* @date 2023/7/2
*/
UserInfo getUserById(@Param("id") Integer id);

使用 #🍂

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where id = #{id}
</select>

使用 $🍂

<select id="getUserById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where id = ${id}
</select>

运行结果🍂

均可正常运行

根据 username 查询用户信息


/**
* 根据 username 查询用户信息
* @author bibubibu
* @date 2023/7/3
*/
List<UserInfo> getUserByName(@Param("username") String username);

使用 #🍂

<select id="getUserByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username = #{username}
</select>

使用 $🍂

<select id="getUserByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username = ${username}
</select>

运行结果🍂

使用 # 正常运行

使用 $ 无法正常运行

根据 id 进行排序


排序有 2 种类型

  • 升序 → asc
  • 降序 → desc

此处以降序举例

/**
* 根据 Id 进行排序
* @author bibubibu
* @date 2023/7/3
*/
List<UserInfo> getUserOrderById(@Param("order") String order);

使用 #🍂

<select id="getUserOrderById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo order by id #{order}
</select>

使用 $🍂

<select id="getUserOrderById" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo order by id ${order}
</select>

运行结果🍂

使用 # 无法正常运行

使用 $ 正常运行

总结


  • #{} → 编译预处理, 不存在 SQL 注入问题
  • ${} → 直接替换, 存在 SQL 注入问题

使用 $ 的注意事项🍂

一定是可穷举的值(例如关键字…), 在使用之前要对传递的值进行安全性验证


编译预处理是指 MyBatis 在处理 #{ } 时, 将 SQL 中的 #{ } 替换为 ?

直接替换是指 MyBatis 在处理 #{ } 时, 将 SQL 中的 #{ } 替换为参数的值

  • 根据 id 查询用户信息🍂
  • #{} → 将#{id}替换为?, 参数为 Integer id, 赋值 ? 为对应类型的值(数值型数据无需'')
  • ${}→ 将${id}替换为对应的 Integer id 的值
  • 即针对数值形数据, #{}无需添加''(也可理解为直接替换的一种方式), 因此利用#可以运行成功
  • select * from userinfo where id = 1(✔)
  • 即针对数值形数据, ${}直接替换, 因此利用$可以运行成功
  • select * from userinfo where id = 1(✔)
  • 根据 username 查询用户信息🍂
  • #{} → 将#{username}替换为?, 参数为 String username, 赋值 ? 为对应类型的值(字符串型数据需'')
  • ${}→ 将${username}替换为对应的 String username 的值
  • 即针对字符串型数据, #{}会添加'', 因此利用#可以运行成功
  • select * from username where username = 'Tom'(✔)
  • 即针对字符串型数据, ${}直接替换, 因此利用$无法运行成功
  • select * from username where username = Tom(✘)
  • 根据 id 进行排序🍂
  • #{} → 将#{order}替换为?, 参数为 String order, 赋值 ? 为对应类型的值(字符串型数据需'')
  • ${}→ 将${order}替换为对应的 String order 的值
  • 即针对字符串型数据, #{}会添加'', 因此利用#无法运行成功(关键字无需添加'')
  • select * from userinfo order by id 'desc'(✘)
  • 即针对字符串型数据, ${}直接替换, 因此利用$可以运行成功(关键字无需添加'')
  • select * from userinfo order by id desc(✔)

简单来说就是针对不同的内容

#{}可能会对参数添加''(字符串型), 也可能是直接替换(数值型)

${}直接替换为对应参数的内容


SQL 注入


既然 # 对于字符串型数据会添加'', 那使用 $ 时对于字符串型手动添加''不可以么

使用 $ 是不安全的, 可能会引起 SQL 注入问题


什么是 SQL 注入?

举个栗子🌰

userinfo 表中的内容🍂

定义一个 login 方法🍂

UserInfo login(@Param("username") String username, @Param("password") String password);

实现该方法🍂

(对于字符串型手动添加'')

<select id="login" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username = '${username}' and password = '${password}'
</select>

单元测试查看结果🍂

登录成功

修改密码后查看结果🍂

登录失败

利用 SQL 注入登录(使用错误的密码)🍂

登录成功

注意此时的密码

String password = "' or 1 = '1";

最终生成的 SQL 语句

select * from userinfo where username = 'admin' and password = '' or 1 = '1'

划分为 2 部分(优先级 → and > or)

username = 'admin' and password = '' / 1 = '1'

因此可以成功登录

🌸上述即为 SQL 注入, 因此推荐使用 # 而不是 $🌸


🔎like 查询


like 查询 → 此处使用的数据表为 userinfo(用户) 表

数据表中的数据

根据 username 查询用户信息


在 Interface 中定义方法🍂

/**
* Like 查询
* @author bibubibu
* @date 2023/7/3
*/
List<UserInfo> getListByName(@Param("username") String username);

在 xml 中实现方法🍂

<select id="getListByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username like '%#{username}%'
</select>

单元测试验证效果🍂

Error → 这是因为使用 # 处理字符串类型时, SQL 语句会添加''

即上述 SQL 语句变为select * from userinfo where username like '%'a'%'

期望的效果是select * from userinfo where username like '%a%'

可能有的小伙伴会说, 那可以用 $ 处理呀

不可以, 还记得上面说的使用 $ 时的注意事项么

使用 $ 时的注意事项 → 一定是可穷举的值(例如关键字…), 而 username 无法穷举, 因此应避免使用 $

使用 # 时的解决办法


解决办法 → 利用 concat() 进行拼接

<select id="getListByName" resultType="com.example.demo.entity.UserInfo">
    select * from userinfo where username like concat('%', #{username}, '%')
</select>

对比🍂

select * from userinfo where username like '%#{username}%'

select * from userinfo where username like concat('%', #{username}, '%')

单元测试验证效果🍂

相关文章
|
17天前
|
SQL Java 数据库连接
深入 MyBatis-Plus 插件:解锁高级数据库功能
Mybatis-Plus 提供了丰富的插件机制,这些插件可以帮助开发者更方便地扩展 Mybatis 的功能,提升开发效率、优化性能和实现一些常用的功能。
101 26
深入 MyBatis-Plus 插件:解锁高级数据库功能
|
22天前
|
SQL 安全 Java
MyBatis-Plus条件构造器:构建安全、高效的数据库查询
MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。
13 1
MyBatis-Plus条件构造器:构建安全、高效的数据库查询
|
1月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
80 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
1月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
46 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
3月前
|
SQL 关系型数据库 MySQL
解决:Mybatis-plus向数据库插入数据的时候 报You have an error in your SQL syntax
该博客文章讨论了在使用Mybatis-Plus向数据库插入数据时遇到的一个常见问题:SQL语法错误。作者发现错误是由于数据库字段中使用了MySQL的关键字,导致SQL语句执行失败。解决方法是将这些关键字替换为其他字段名称,以避免语法错误。文章通过截图展示了具体的操作步骤。
|
3月前
|
XML SQL JavaScript
在vue页面引入echarts,图表的数据来自数据库 springboot+mybatis+vue+elementui+echarts实现图表的制作
这篇文章介绍了如何在Vue页面中结合SpringBoot、MyBatis、ElementUI和ECharts,实现从数据库获取数据并展示为图表的过程,包括前端和后端的代码实现以及遇到的问题和解决方法。
在vue页面引入echarts,图表的数据来自数据库 springboot+mybatis+vue+elementui+echarts实现图表的制作
|
3月前
|
druid Java 数据库连接
SpringBoot项目整合MybatisPlus持久层框架+Druid数据库连接池,以及实现增删改查功能
SpringBoot项目整合MybatisPlus和Druid数据库连接池,实现基本的增删改查功能。
341 0
|
4月前
|
Oracle 关系型数据库 Java
实时计算 Flink版操作报错合集之cdc postgres数据库,当表行记录修改后报错,该如何修改
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
SQL 监控 关系型数据库
实时计算 Flink版操作报错合集之在设置监控PostgreSQL数据库时,将wal_level设置为logical,出现一些表更新和删除操作报错,怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
4月前
|
关系型数据库 Java 数据库
实时计算 Flink版操作报错合集之flinksql采PG数据库时报错,该如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
下一篇
无影云桌面