重新建设网站的申请报告,店面设计效果图大全,seo排名软件价格,网站建设维护 微信目录
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. …目录
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 version1.0 encodingUTF-8?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.example.demo.mapper.UserMapperselect idqueryAll resultTypecom.example.demo.model.Userselect * from userinfo/select
/mapper
接下来在 UserMapper 类中添加查找方法
Mapper
public interface UserMapper {ListUser queryAll();
}
在上述类的方法中右键选择生成选择测试即可生成测试类。接下来在 UserMapperTest 类中进行自测
Slf4j
SpringBootTest
class UserMapperTest {Autowiredprivate UserMapper userMapper;Testvoid queryAll() {ListUser users userMapper.queryAll();log.info(users.toString());}
}
运行结果如下图所示可以看到查找到了数据库中现有的所有数据 1.2 通过 id 进行查找
首先我们在 UserMapper.xml 文件中添加以下内容
?xml version1.0 encodingUTF-8?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.example.demo.mapper.UserMapperselect idqueryAll resultTypecom.example.demo.model.Userselect * from userinfo/selectselect idqueryById resultTypecom.example.demo.model.Userselect * from userinfo where id ?/select
/mapper
接下来在 UserMapper 类中添加查找方法
Mapper
public interface UserMapper {// 查询所有数据ListUser queryAll();// 通过 id 查询数据User queryById(Param(uid) Integer id);
} 在上述类的方法中右键选择生成选择测试生成测试类 可以看到生成的测试类中包含以下方法 接下来我们编写测试的代码
Slf4j
SpringBootTest
class UserMapperTest {Autowiredprivate UserMapper userMapper;Testvoid queryAll() {ListUser 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 idinsertinsert into userinfo (username,password,photo)values(#{username},#{password},#{photo})
/insert
在 UserMapper 类中添加插入方法
Mapper
public interface UserMapper {// 查询所有数据ListUser queryAll();// 通过 id 查询数据User queryById(Param(uid) Integer id);// 插入数据Integer insert(User user);
}
在上述类的方法中右键选择生成选择测试即可生成测试类编写测试方法
Slf4j
SpringBootTest
class UserMapperTest {Autowiredprivate UserMapper userMapper;Testvoid queryAll() {ListUser 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 idinsert2insert 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 idinsert2 useGeneratedKeystrue keyPropertyidinsert 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 idupdateupdate userinfo set username #{username},password #{password} where id #{id}/update
在 UserMapper 类中添加修改方法
Mapper
public interface UserMapper {// 查询所有数据ListUser 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 iddeletedelete from userinfo where id #{id}/delete
在 UserMapper 类中添加修改方法
Mapper
public interface UserMapper {// 查询所有数据ListUser 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 idqueryById resultTypecom.example.demo.model.Userselect * from userinfo where id ${uid}/select
可以看到依然可以查询到数据 接下来我们使用 # 通过名称来查询
User queryByName(String name); select idqueryByName resultTypecom.example.demo.model.Userselect * from userinfo where username #{username}/select
Testvoid queryByName() {log.info(queryByName...);User user userMapper.queryByName(Jenny);log.info(user.toString());}
可以看到成功查询到数据 接下来我们使用 $ 通过名称来查询
修改 xml 文件
select idqueryByName resultTypecom.example.demo.model.Userselect * from userinfo where username ${username}/select
运行代码后出现以下报错 是因为 $ 符号传递的参数是没有加引号直接放在参数中的。
那么如果我们自行添加引号呢
select idqueryByName resultTypecom.example.demo.model.Userselect * from userinfo where username ${username}/select
此时我们可以看到成功运行了 综上我们来看一下其中的本质原因
#{} 预编译处理占位${}字符直接替换字符的内容直接当作 SQL 的一部分来运行SQL 注入影响程序的安全 当我们执行以下 SQL 语句时会发现数据库中的所有数据都被查出来了
SELECT * FROM userinfo where username or 1 1 5.1 SQL 注入 用户登录
我们先在数据库中保留以下信息 我们先来测试 # 正确查询
select idqueryByNameAndPassword resultTypecom.example.demo.model.Userselect * 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(usernull?null:user.toString());}
可以看到查询为空 接下来测试 SQL 注入的情况
Testvoid queryByNameAndPassword() {String username admin;String password or 1 1;User user userMapper.queryByNameAndPassword(username,password);log.info(usernull?null:user.toString());}
可以看到使用错误的 password 显示为 null 数据没有被查询出来 接下来测试 $ 正确查询
select idqueryByNameAndPassword resultTypecom.example.demo.model.Userselect * 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(usernull?null:user.toString());}
可以看到成功查询到 接下来我们输入错误的 password :
Testvoid queryByNameAndPassword() {String username admin;String password admin123;User user userMapper.queryByNameAndPassword(username,password);log.info(usernull?null:user.toString());}
可以看到没有查询到数据显示为 null 接下来我们来看 SQL 注入的情况
Testvoid queryByNameAndPassword() {String username admin;String password or 1 1;User user userMapper.queryByNameAndPassword(username,password);log.info(usernull?null:user.toString());} 可以看到数据仍然被查询出来了
那么 SQL 注入简单来说就是将本来不该被查询出来的数据查询出来了。
6. Spring Boot 打印 SQL 日志
添加配置文件
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 可以看到直接将对应的 SQL 语句打印在了控制台 以上就是 $ 打印的结果是直接进行替换了。
接下来我们看一下 # 打印的结果 所以# 就是进行预编译采用占位的方式。
7. order by 排序
我们先来看一下此时数据库中的数据 接下来我们根据 id 进行降序排列
ListUser queryByOrder(String order);
select idqueryByOrder resultTypecom.example.demo.model.Userselect * from userinfo order by id #{order}/select
Testvoid queryByOrder() {ListUser users userMapper.queryByOrder(desc);log.info(users.toString());}
我们可以看到运行之后的结果并没有像我们想象之中的那样降序排列而是直接报错 那么上述这种情况下就无法使用 # 必须使用 $ 符号才可以。
所以排序时只能使用 $。
修改 xml 文件 select idqueryByOrder resultTypecom.example.demo.model.Userselect * from userinfo order by id ${order}/select
此时可以看到成功进行了降序排列 但是只要使用了 $ 就存在 SQL 注入的问题该如何解决呢 要从根源上解决以上问题就是不让用户输入 SQL 语句用户只能点击参数由后端进行拼接后端在查询之前对参数进行校验只能传两个值desc降序 和 asc升序。 8. like 查询
我们先来看一下 SQL 语句的 like 查询
SELECT * FROM userinfo where username like %m%; 接下来我们使用 # 来查询
ListUser queryByLike(String name);
select idqueryByLike resultTypecom.example.demo.model.UserSELECT * FROM userinfo where username like %#{name}%;/select
Testvoid queryByLike() {ListUser users userMapper.queryByLike(m);log.info(users.toString());}
可以看到无法正确查询 接下来我们改成 $ 进行查询 select idqueryByLike resultTypecom.example.demo.model.UserSELECT * FROM userinfo where username like %${name}%;/select
此时我们可以看到查询到了数据 但是使用了 $ 就存在 SQL 注入的问题因此我们需要使用 MySQL 的一个内置函数。
SELECT * FROM userinfo where username like concat(%,m,%);
可以看到使用以上 SQL 语句也可以进行查询 因此我们修改 xml 文件如下
select idqueryByLike resultTypecom.example.demo.model.UserSELECT * FROM userinfo where username like concat(%,#{name},%);/select
可以看到使用 concat 函数后可以查询成功 9. 通过页面返回数据 新建 UserController 类
RestController
RequestMapping(/user)
public class UserController {Autowiredprivate UserService userService;RequestMapping(/selectAll)public ListUser selectAllUser(){return userService.selectAllUser();}
} 新建 UserService 类
Service
public class UserService {Autowiredprivate UserMapper userMapper;public ListUser selectAllUser() {return userMapper.queryAll();}
}
接下来我们运行启动类即可在页面中看到查找的数据库信息
10. 总结
$ 存在 SQL 注入问题因为 # 是预编译而 $ 是字符替换orde by 只能使用 $通过后端控制参数的输入只能为 desc 和 asc# 直接用于 like 查询会报错需要使用 MySQL 的内置函数 concat 进行字符连接。