11. Mybatis 的增删查改【万字详解】

目录

1. 数据的查找 select

1.1 查询所有数据

1.2 通过 id 进行查找

2. 插入数据 insert

3. 修改数据 update

4. 删除数据 delete

5. $ 和 # 的区别

5.1 SQL 注入 用户登录

6. Spring Boot 打印 SQL 日志

7. order by 排序

8. like 查询

9. 通过页面返回数据

10. 总结


在上篇文章中我们介绍了 mybatis 的相关概念,通过 mybatis 对数据库中的数据进行查找,接下来我们将具体的介绍 Mybatis 的增删查改。

同时本篇文章还详细介绍了 $ 和 # 的区别(重点)。

1. 数据的查找 select

1.1 查询所有数据

通过 workbench,我们可以看到数据库中的现有数据:

 接下来我们在 UserMapper.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.example.demo.mapper.UserMapper"><select id="queryAll" resultType="com.example.demo.model.User">select * from userinfo</select>
</mapper>

接下来在 UserMapper 类中添加查找方法: 

@Mapper
public interface UserMapper {List<User> queryAll();
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类。接下来,在 UserMapperTest 类中进行自测: 

@Slf4j
@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testvoid queryAll() {List<User> users = userMapper.queryAll();log.info(users.toString());}
}

运行结果如下图所示,可以看到查找到了数据库中现有的所有数据: 

1.2 通过 id 进行查找

首先,我们在 UserMapper.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.example.demo.mapper.UserMapper"><select id="queryAll" resultType="com.example.demo.model.User">select * from userinfo</select><select id="queryById" resultType="com.example.demo.model.User">select * from userinfo where id = ?</select>
</mapper>

接下来在 UserMapper 类中添加查找方法: 

@Mapper
public interface UserMapper {// 查询所有数据List<User> queryAll();// 通过 id 查询数据User queryById(@Param("uid") Integer id);
}

 在上述类的方法中右键,选择生成,选择测试,生成测试类:

 可以看到生成的测试类中包含以下方法:

接下来,我们编写测试的代码:

@Slf4j
@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testvoid queryAll() {List<User> users = userMapper.queryAll();log.info(users.toString());}@BeforeEachvoid setUp() {log.info("before...");}@AfterEachvoid tearDown() {log.info("after...");}@Testvoid queryById() {log.info("queryById...");User user = userMapper.queryById(1);log.info(user.toString());}
}

运行结果如下: 

需要注意的是,当我们只有一个参数时,可以不写注解;但是写了注解时,SQL 语句需要和注解中使用的参数保持一致

当只有一个参数时,不仅可以不写参数,参数的名称也可以不同,以下两条语句均可以成功执行:

User queryById(Integer id);
User queryById(Integer aaa);

2. 插入数据 insert

我们先来看一下数据库中都有哪些数据:

可以看到 id 是自增的,createtime 和 updatetime 都是当前时间,因此我们在插入数据时不用添加。

接下来我们在 UserMapper.xml 文件中添加以下内容:

<insert id="insert">insert into userinfo (username,password,photo)values(#{username},#{password},#{photo})
</insert>

在 UserMapper 类中添加插入方法: 

@Mapper
public interface UserMapper {// 查询所有数据List<User> queryAll();// 通过 id 查询数据User queryById(@Param("uid") Integer id);// 插入数据Integer insert(User user);
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:

@Slf4j
@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testvoid queryAll() {List<User> users = userMapper.queryAll();log.info(users.toString());}@BeforeEachvoid setUp() {log.info("before...");}@AfterEachvoid tearDown() {log.info("after...");}@Testvoid queryById() {log.info("queryById...");User user = userMapper.queryById(1);log.info(user.toString());}@Testvoid insert() {User user = new User();user.setUsername("Danny");user.setPassword("123456");user.setPhoto("123");Integer result = userMapper.insert(user);log.info("insert result:"+ result);}
}

接下来,在 UserMapperTest 类中进行自测: 

 在 workbench 中可以看到数据插入成功:


还可以通过第二种方法插入数据:

Integer insert2(@Param(("userinfo")) User user);
 <insert id="insert2">insert into userinfo (username,password,photo)values(#{userinfo.username},#{userinfo.password},#{userinfo.photo})</insert>

 添加测试方法:

 @Testvoid insert2() {User user = new User();user.setUsername("Danny");user.setPassword("123456");user.setPhoto("123");Integer result = userMapper.insert2(user);log.info("insert result:"+ result);}

可以看到,同样能够运行成功:

需要注意的是,如果使用了 @Param 注解,就必须使用 @Param 注解的命名

获取自增 id

在 UserMapper.xml 文件中添加以下内容:

<insert id="insert2" useGeneratedKeys="true" keyProperty="id">insert into userinfo (username,password,photo)values(#{userinfo.username},#{userinfo.password},#{userinfo.photo})</insert>

在 UserMapperTest 类中添加以下内容:

@Testvoid insert2() {User user = new User();user.setUsername("Danny");user.setPassword("123456");user.setPhoto("123");Integer result = userMapper.insert2(user);log.info("insert result:"+ result + ", 自增id:" + user.getId());}

此时可以看到自增 id 为:5. 

3. 修改数据 update

在修改数据库的数据之前,我们先来看一下此时数据库中的数据:

接下来我们修改 id = 3 的这行数据:

在 UserMapper.xml 文件中添加以下内容:

<update id="update">update userinfo set username = #{username},password = #{password} where id = #{id}</update>

在 UserMapper 类中添加修改方法:

@Mapper
public interface UserMapper {// 查询所有数据List<User> queryAll();// 通过 id 查询数据User queryById(@Param("uid") Integer id);// 插入数据Integer insert(User user);Integer insert2(@Param(("userinfo")) User user);// 修改数据void update(User user);
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:

 @Testvoid update() {User user = new User();user.setId(3);user.setUsername("Jenny");user.setPassword("root123456");userMapper.update(user);}

接下来,在 UserMapperTest 类中进行自测: 

运行成功后,可以看到数据库中 id =3 这一行的数据已经被修改了:

4. 删除数据 delete

我们先来看一下此时数据库中的数据:

接下来我们删除 id = 4 的这行数据:

在 UserMapper.xml 文件中添加以下内容:

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

在 UserMapper 类中添加修改方法: 

@Mapper
public interface UserMapper {// 查询所有数据List<User> queryAll();// 通过 id 查询数据User queryById(@Param("uid") Integer id);// 插入数据Integer insert(User user);Integer insert2(@Param(("userinfo")) User user);// 修改数据void update(User user);// 通过 id 删除数据void delete(Integer id);
}

在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:

 @Testvoid delete() {userMapper.delete(4);}

接下来,在 UserMapperTest 类中进行自测: 

运行成功后,可以看到数据库中 id =4 这一行的数据已经被删除了:

5. $ 和 # 的区别

我们将通过 id 查询的 xml 文件中的 # 改成 $:

 <select id="queryById" resultType="com.example.demo.model.User">select * from userinfo where id = ${uid}</select>

可以看到依然可以查询到数据: 

接下来我们使用 # 通过名称来查询:

User queryByName(String name);
 <select id="queryByName" resultType="com.example.demo.model.User">select * from userinfo where username = #{username}</select>
@Testvoid queryByName() {log.info("queryByName...");User user = userMapper.queryByName("Jenny");log.info(user.toString());}

可以看到成功查询到数据: 

接下来我们使用 $ 通过名称来查询:

修改 xml 文件:

<select id="queryByName" resultType="com.example.demo.model.User">select * from userinfo where username = ${username}</select>

运行代码后出现以下报错:

是因为 $ 符号传递的参数是没有加引号,直接放在参数中的

那么,如果我们自行添加引号呢?

<select id="queryByName" resultType="com.example.demo.model.User">select * from userinfo where username = '${username}'</select>

此时我们可以看到成功运行了: 

综上,我们来看一下其中的本质原因:

  • #{} :预编译处理(占位)
  • ${}:字符直接替换(字符的内容直接当作 SQL 的一部分来运行,SQL 注入影响程序的安全

 当我们执行以下 SQL 语句时,会发现数据库中的所有数据都被查出来了:

SELECT * FROM userinfo where username = '' or 1 = '1'

5.1 SQL 注入 用户登录

我们先在数据库中保留以下信息:

我们先来测试 # 正确查询:

<select id="queryByNameAndPassword" resultType="com.example.demo.model.User">select * from userinfo where username = #{username} and password = #{password}</select>
User queryByNameAndPassword(@Param("username") String username,@Param("password") String password);
 @Testvoid queryByNameAndPassword() {String username = "admin";String password = "admin";User user = userMapper.queryByNameAndPassword(username,password);log.info(user.toString());}

可以看到查询成功: 

再来测试 # 错误查询,直接修改测试方法:

@Testvoid queryByNameAndPassword() {String username = "admin";String password = "admin123";User user = userMapper.queryByNameAndPassword(username,password);log.info(user==null?null:user.toString());}

可以看到查询为空:

接下来测试 SQL 注入的情况:

@Testvoid queryByNameAndPassword() {String username = "admin";String password = "'or 1 ='1";User user = userMapper.queryByNameAndPassword(username,password);log.info(user==null?null:user.toString());}

可以看到使用错误的 password 显示为 null ,数据没有被查询出来:


接下来测试 $ 正确查询:

<select id="queryByNameAndPassword" resultType="com.example.demo.model.User">select * from userinfo where username = '${username}' and password = '${password}'</select>
@Testvoid queryByNameAndPassword() {String username = "admin";String password = "admin";User user = userMapper.queryByNameAndPassword(username,password);log.info(user==null?null:user.toString());}

可以看到成功查询到: 

接下来我们输入错误的 password :

@Testvoid queryByNameAndPassword() {String username = "admin";String password = "admin123";User user = userMapper.queryByNameAndPassword(username,password);log.info(user==null?null:user.toString());}

可以看到没有查询到数据,显示为 null: 

接下来我们来看 SQL 注入的情况:

@Testvoid queryByNameAndPassword() {String username = "admin";String password = "'or 1 ='1";User user = userMapper.queryByNameAndPassword(username,password);log.info(user==null?null:user.toString());}

 可以看到数据仍然被查询出来了:

那么 SQL 注入简单来说就是将本来不该被查询出来的数据,查询出来了。

6. Spring Boot 打印 SQL 日志

添加配置文件:

mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

可以看到直接将对应的 SQL 语句打印在了控制台:

以上就是 $ 打印的结果,是直接进行替换了。

接下来我们看一下 # 打印的结果:

所以,# 就是进行预编译,采用占位的方式。

7. order by 排序

我们先来看一下此时数据库中的数据:

接下来我们根据 id 进行降序排列:

List<User> queryByOrder(String order);
<select id="queryByOrder" resultType="com.example.demo.model.User">select * from userinfo order by id #{order}</select>
@Testvoid queryByOrder() {List<User> users = userMapper.queryByOrder("desc");log.info(users.toString());}

我们可以看到运行之后的结果并没有像我们想象之中的那样降序排列,而是直接报错:

那么上述这种情况下,就无法使用 # 必须使用 $ 符号才可以。

所以排序时只能使用 $。

修改 xml 文件:

 <select id="queryByOrder" resultType="com.example.demo.model.User">select * from userinfo order by id ${order}</select>

此时可以看到成功进行了降序排列:

但是只要使用了 $ 就存在 SQL 注入的问题,该如何解决呢?

要从根源上解决以上问题就是不让用户输入 SQL 语句,用户只能点击,参数由后端进行拼接,后端在查询之前,对参数进行校验,只能传两个值:desc(降序) 和 asc(升序)。

8. like 查询

我们先来看一下 SQL 语句的 like 查询:

SELECT * FROM userinfo where username like "%m%";

接下来我们使用 # 来查询: 

List<User> queryByLike(String name);
<select id="queryByLike" resultType="com.example.demo.model.User">SELECT * FROM userinfo where username like '%#{name}%';</select>
@Testvoid queryByLike() {List<User> users = userMapper.queryByLike("m");log.info(users.toString());}

可以看到无法正确查询: 

接下来我们改成 $ 进行查询:

 <select id="queryByLike" resultType="com.example.demo.model.User">SELECT * FROM userinfo where username like '%${name}%';</select>

此时,我们可以看到查询到了数据: 

但是使用了 $ 就存在 SQL 注入的问题,因此我们需要使用 MySQL 的一个内置函数。

SELECT * FROM userinfo where username like concat('%','m','%');

可以看到使用以上 SQL 语句也可以进行查询: 

因此,我们修改 xml 文件如下:

<select id="queryByLike" resultType="com.example.demo.model.User">SELECT * FROM userinfo where username like concat('%',#{name},'%');</select>

可以看到使用 concat 函数后可以查询成功:

9. 通过页面返回数据

新建 UserController 类: 

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/selectAll")public List<User> selectAllUser(){return userService.selectAllUser();}
}

 新建 UserService 类:

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public List<User> selectAllUser() {return userMapper.queryAll();}
}

接下来我们运行启动类,即可在页面中看到查找的数据库信息: 

10. 总结

  1. $ 存在 SQL 注入问题,因为 # 是预编译而 $ 是字符替换;
  2. orde by 只能使用 $,通过后端控制参数的输入(只能为 desc 和 asc);
  3. # 直接用于 like 查询会报错,需要使用 MySQL 的内置函数 concat 进行字符连接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法基础:动态规划】5.3 计数类DP(整数拆分、分拆数)

文章目录 例题&#xff1a;900. 整数划分解法1——完全背包解法2——分拆数⭐⭐⭐ 例题&#xff1a;900. 整数划分 https://www.acwing.com/problem/content/902/ 解法1——完全背包 容量是 n&#xff0c;物品的大小和价值是 1 ~ n 中的所有数字。 import java.util.*;pub…

【JAVASE】循环结构

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 循环 1. 循环结构1.1 while 循环1.2 bre…

招商银行秋招攻略和考试内容详解

招商银行秋招简介 招商银行是一家股份制商业银行&#xff0c;银行的服务理念已经深入人心&#xff0c;在社会竞争愈来愈烈的今天&#xff0c;招商银行的招牌无疑是个香饽饽&#xff0c;很多人也慕名而至&#xff0c;纷纷向招商银行投出了简历。那么秋招银行的秋招开始时间是多…

支持向量机(iris)

代码&#xff1a; import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn import svm import numpy as np# 定义每一列的属性 colnames [sepal-length, sepal-width, petal-length, petal-width, class] # 读取数据 iris pd.read_csv(data\\i…

消息队列总结(4)- RabbitMQ Kafka RocketMQ高性能方案

1.RabbitMQ的高性能解决方案 1.1 发布确认机制 RabbitMQ提供了3种生产者发布确认的模式&#xff1a; 简单模式&#xff08;Simple Mode&#xff09;&#xff1a;生产者发送消息后&#xff0c;等待服务器确认消息已经被接收。这种模式下&#xff0c;生产者发送消息后会阻塞&am…

论文笔记--Skip-Thought Vectors

论文笔记--Skip-Thought Vectors 1. 文章简介2. 文章概括3 文章重点技术3.1 Skip Thought Vectors3.2 词表拓展 4. 文章亮点5. 原文传送门6. References 1. 文章简介 标题&#xff1a;Skip-Thought Vectors作者&#xff1a;Ryan Kiros, Yukun Zhu, Ruslan Salakhutdinov, Rich…

JavaSE复盘2

Collection接口的接口对象集合&#xff08;单列集合&#xff09; List接口&#xff1a;元素按照先后有序保存&#xff0c;可重复 LinkList接口实现类&#xff0c;链表&#xff0c;随机访问&#xff0c;没有同步&#xff0c;线程不安全ArrayList接口实现类&#xff0c;数组&…

element时间选择器的默认值

概览&#xff1a;vue使用element组件&#xff0c;需要给时间选择器设置默认值&#xff0c;场景一&#xff1a;默认时间选择器&#xff0c;场景二&#xff1a;时间范围选择器&#xff0c;开始时间和结束时间。 一、默认时间选择器 实现思路&#xff1a; element组件的v-model绑…

忘记安卓图案/密码锁如何解锁?

如何解锁Android手机图案锁&#xff1f;如何删除忘记的密码&#xff1f;Android 手机锁定后如何重置&#xff1f;这是许多智能手机用户在网上提出的几个问题。为了回答这些问题&#xff0c;我们想出了一些简单有效的方法来解锁任何设备而不丢失数据。 忘记手机密码可能会令人恐…

web服务器(Tomcat)

目录 一、web服务器 1. 常见web服务器 2. web服务器简介 二、 Apache Tomcat服务器 1. Tomcat服务器简介 2. Tomcat服务器基本使用 3. 启动tomcat常见问题 &#xff08;1&#xff09;启动tomcat控制台乱码 &#xff08;2&#xff09;启动tomcat闪退问题 &#xff08;…

爬虫003_pycharm的安装以及使用_以及python脚本模版设置---python工作笔记021

这里我们用ide,pycharm来编码,看一看如何下载 这里我们下载这个社区办,这个是免费的,个人版是收费的 然后勾选以后 安装以后我们来创建一个项目 这里可以选择python的解释器,选择右边的... 这里我们找到我们自己安装的python解释器

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境4

7、使用串口工具 &#xff08;1&#xff09;连接硬件 连接 Type C 线&#xff0c; 一端电脑一端开发板 查看设备是否已经正确识别&#xff1a; 在 Windows 下可以打开设备管理器来查看 如果没有发现设备&#xff0c; 需要确认有没有装驱动以及接触是否良好 &#xff08;2&a…

【JVM】详解JVM的五大内存模型、可能出现的异常以及堆栈引用易错点

文章目录 1、堆(线程共享)2、方法区(线程共享)3、虚拟机栈&#xff08;线程私有&#xff09;4、本地方法栈(线程私有)5、程序计数器(线程私有)6、易错点 源自&#xff1a;深入理解Java虚拟机&#xff1a;JVM高级特性与最佳实践&#xff08;第3版&#xff09; 周志明 1、堆(线程…

C语言第十一课--------操作符的使用与分类-------基本操作

作者前言 作者介绍&#xff1a; 作者id&#xff1a;老秦包你会&#xff0c; 简单介绍&#xff1a; 喜欢学习C语言和python等编程语言&#xff0c;是一位爱分享的博主&#xff0c;有兴趣的小可爱可以来互讨 个人主页::小小页面 gitee页面:秦大大 一个爱分享的小博主 欢迎小可爱们…

css 书写规范!其他人总结!

CSS书写顺序 1.位置属性(position, top, right, z-index, display, float等) 2.大小(width, height, padding, margin) 3.文字系列(font, line-height, letter-spacing, color- text-align等) 4.背景(background, border等) 5.其他(animation, transition等) CSS书写规范 使用…

MyBatis-Plus自定义sql注入器

文章目录 一、前言二、MyBatis-Plus自定义sql注入器功能实现2.1、编写自定义sql类2.2、将自定义sql添加到BaseMapper中2.3、编写自己的sql注入器 一、前言 在日常开发过程中&#xff0c;我们可能会发现 MyBatis-Plus 提供的那些自带的 sql 语句无法满足我们的开发需求&#xf…

web自动化测试进阶篇05 ——— 界面交互场景测试

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

【Ajax】笔记-同源策略

同源策略(Same-Origin Policy)&#xff0c;是浏览器的一种安全策略 同源&#xff08;即url相同&#xff09;&#xff1a;协议、域名、端口号 必须完全相同。&#xff08;请求是来自同一个服务&#xff09; 跨域&#xff1a;违背了同源策略&#xff0c;即跨域。 ajax请求是遵循…

texshop mac中文版-TeXShop for Mac(Latex编辑预览工具)

texshop for mac是一款可以在苹果电脑MAC OS平台上使用的非常不错的Mac应用软件&#xff0c;texshop for mac是一个非常有用的工具&#xff0c;广泛使用在数学&#xff0c;计算机科学&#xff0c;物理学&#xff0c;经济学等领域的合作&#xff0c;这些程序的标准tetex分布特产…

flask中的session介绍

flask中的session介绍 在Flask中&#xff0c;session是一个用于存储特定用户会话数据的字典对象。它在不同请求之间保存数据。它通过在客户端设置一个签名的cookie&#xff0c;将所有的会话数据存储在客户端。以下是如何在Flask应用中使用session的基本步骤&#xff1a; 首先…