目录
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 {
@Autowired
private UserMapper userMapper;
@Test
void 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 {
@Autowired
private UserMapper userMapper;
@Test
void queryAll() {
List<User> users = userMapper.queryAll();
log.info(users.toString());
}
@BeforeEach
void setUp() {
log.info("before...");
}
@AfterEach
void tearDown() {
log.info("after...");
}
@Test
void 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 {
@Autowired
private UserMapper userMapper;
@Test
void queryAll() {
List<User> users = userMapper.queryAll();
log.info(users.toString());
}
@BeforeEach
void setUp() {
log.info("before...");
}
@AfterEach
void tearDown() {
log.info("after...");
}
@Test
void queryById() {
log.info("queryById...");
User user = userMapper.queryById(1);
log.info(user.toString());
}
@Test
void 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>
添加测试方法:
@Test
void 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 类中添加以下内容:
@Test
void 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);
}
在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:
@Test
void 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);
}
在上述类的方法中右键,选择生成,选择测试,即可生成测试类,编写测试方法:
@Test
void 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>
@Test
void 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);
@Test
void queryByNameAndPassword() {
String username = "admin";
String password = "admin";
User user = userMapper.queryByNameAndPassword(username,password);
log.info(user.toString());
}
可以看到查询成功:
再来测试 # 错误查询,直接修改测试方法:
@Test
void queryByNameAndPassword() {
String username = "admin";
String password = "admin123";
User user = userMapper.queryByNameAndPassword(username,password);
log.info(user==null?null:user.toString());
}
可以看到查询为空:
接下来测试 SQL 注入的情况:
@Test
void 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>
@Test
void queryByNameAndPassword() {
String username = "admin";
String password = "admin";
User user = userMapper.queryByNameAndPassword(username,password);
log.info(user==null?null:user.toString());
}
可以看到成功查询到:
接下来我们输入错误的 password :
@Test
void queryByNameAndPassword() {
String username = "admin";
String password = "admin123";
User user = userMapper.queryByNameAndPassword(username,password);
log.info(user==null?null:user.toString());
}
可以看到没有查询到数据,显示为 null:
接下来我们来看 SQL 注入的情况:
@Test
void 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>
@Test
void 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>
@Test
void 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 {
@Autowired
private UserService userService;
@RequestMapping("/selectAll")
public List<User> selectAllUser(){
return userService.selectAllUser();
}
}
新建 UserService 类:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> selectAllUser() {
return userMapper.queryAll();
}
}
接下来我们运行启动类,即可在页面中看到查找的数据库信息: 文章来源:https://www.toymoban.com/news/detail-615558.html
10. 总结
- $ 存在 SQL 注入问题,因为 # 是预编译而 $ 是字符替换;
- orde by 只能使用 $,通过后端控制参数的输入(只能为 desc 和 asc);
- # 直接用于 like 查询会报错,需要使用 MySQL 的内置函数 concat 进行字符连接。
文章来源地址https://www.toymoban.com/news/detail-615558.html
到了这里,关于11. Mybatis 的增删查改【万字详解】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!