当前位置:   article > 正文

Mybatis:SQL注入问题 like模糊查询 多表查询 动态SQL_mybatis sql like

mybatis sql like

                                                                                                         ----keep moving

目录

一:#{}和${}的区别

 1.1:实例

1.1.1:Mapper中声明的方法:

1.1.2:XML中的配置

1.1.3:生成测试方法+运行结果

二:SQL注入问题 

2.1:实例

2.1.1Mapper中声明的方法

2.1.2:XML中的配置

2.2.3:生成测试方法+运行结果

2.2:由${}引出的SQL注入问题

2.2.1测试的代码

2.2.2: XML中的配置

2.2.3:运行结果:

2.3:什么时候用${}

三:like模糊查询

3.1实例

3.1.1:Mapper中声明的方法

3.1.2:XML中的配置

3.1.3:生成测试方法+运行结果

3.2如何进行解决 

四:多表查询

4.1:当数据库里面的字段名和对象的属性名不一致时

4.1.1解决方案一:

4.1.2解决方案二:(常用的方案)

4.2:一对一多表查询

4.3:一对多查询 

4.4:多对多查询 

五:动态SQL 

5.1:标签 

5.1.1:使用案例 

5.2:标签

5.2.1使用案例 

5.3:标签 

5.4:标签 

 5.4.1使用案例:

5.5:标签

​编辑 5.5.1使用案例:


一:#{}和${}的区别

    在上一篇博客中,我们在博客的末尾简单的总结了#{},${},这两个注解的区别。那么,这篇博客我们来详细的了解两者的区别。

#{}:将其内容加上单引号。

${}:直接进行替换。常用于替换SQL中的关键字,eg:desc/asc。

 1.1:实例

我们按照userinfo的id将用户的信息按降序排序。

1.1.1:Mapper中声明的方法:

  List<UserInfo> getlistByOrder(@Param("order") String order);

1.1.2:XML中的配置

  1. <select id="getlistByOrder" resultType="com.example.demo10.entity.UserInfo">
  2. select * from userinfo order by id ${order}
  3. </select>

1.1.3:生成测试方法+运行结果

  1. @Test
  2. void getlistByOrder() {
  3. String order="desc";
  4. List<UserInfo> userInfos = userMapper.getlistByOrder(order);
  5. for (UserInfo userInfo : userInfos) {
  6. System.out.println(userInfo);
  7. }
  8. }

如上图所示,我们会发现当把order这个字符串传进去的时候,由${}进行处理,此时,直接进行了替换,并没有进行加''。这是最本质的区别。 

二:SQL注入问题 

       从上文我们可以了解到,${}和#{}最本质的区别是一个加了单引号,一个直接进行替换。那么,如果我们将#{}替换成${}会发生什么?下面,我们将利用登录这一假设的实例:

2.1:实例

2.1.1Mapper中声明的方法

  1. //输入用户的账户和密码
  2. UserInfo login(@Param("username") String username,@Param("password")String password);

2.1.2:XML中的配置

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

2.2.3:生成测试方法+运行结果

  1. @Test
  2. void login() {
  3. String username="李明轩";
  4. String password="123456";
  5. UserInfo login = userMapper.login(username, password);
  6. System.out.println(login==null?"失败":"成功");
  7. }

从测试用例不难看出,SQL语句出问题了,可见,${}是直接进行替换的。那么,我们在${}加上单引号呢?

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

 运行成功:从这一实例不难看出,${}是直接替换的,加上单引号之后,就和#{}拥有一样的功能了。

2.2:由${}引出的SQL注入问题

2.2.1测试的代码

  1. @Test
  2. void login() {
  3. String username="李明轩";
  4. String password="'or 1= '1 ";
  5. UserInfo login = userMapper.login(username, password);
  6. System.out.println(login==null?"失败":"成功");
  7. }

2.2.2: XML中的配置

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

2.2.3:运行结果:

 通过上述测试,我们发现当用户存在时,密码不正确时,同样也可以将其用户信息打印出来,为什么呢?

2.3:什么时候用${}

三:like模糊查询

 在前面我们学习SQL语句中,有模糊查询,为like。我们在mybatis来使用一下like查询。

3.1实例

3.1.1:Mapper中声明的方法

  1. //查询用户名字中含有李的用户信息
  2. List<UserInfo> getListByName(String username);

3.1.2:XML中的配置

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

3.1.3:生成测试方法+运行结果

  1. @Test
  2. void getListByName() {
  3. String username="李";
  4. List<UserInfo> userInfos = userMapper.getListByName(username);
  5. System.out.println(userInfos);
  6. }

我们会发现,当这样运行的时候,SQL语句会爆出错误,为什么呢?

3.2如何进行解决 

利用mysql中提供的concat进行拼接。我们来进行验证。

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

 运行结果:

可见,当我们使用SQL语句中的普通的like模糊查询时,要注意利用concat进行拼接。

四:多表查询

4.1:当数据库里面的字段名和对象的属性名不一致时

看如下两张图:我们会发现数据库中的字段名的username和对象的 name不一致,我们该如何解决?

数据库中的字段名:

对象的属性名:

  1. @Data
  2. public class UserInfo {
  3. private int id;
  4. private String name;
  5. private String password;
  6. private String photo;
  7. private LocalDateTime createtime;
  8. private LocalDateTime updatetime;
  9. private int state;
  10. }

4.1.1解决方案一:

首先在*Mapper.xml声明对ResultMap的配置:

  1. <resultMap id="baseMap" type="com.example.demo10.entity.UserInfo">
  2. <id column="id" property="id"></id>
  3. <result column="usernmae" property="name"></result>
  4. <result column="password" property="password"></result>
  5. <result column="photo" property="photo"></result>
  6. <result column="createtime" property="createtime"></result>
  7. <result column="updatetime" property="updatetime"></result>
  8. <result column="state" property="state"></result>
  9. </resultMap>

  1. <select id="getAll1" resultMap="baseMap">
  2. select * from userinfo;
  3. </select>

Mapper中的声明方法:

 

  1. //查询所有的用户
  2. List<UserInfo> getAll1();

生成测试方法+运行结果:

  1. @Test
  2. void getAll1() {
  3. List<UserInfo> all1 = userMapper.getAll1();
  4. for (UserInfo userInfo : all1) {
  5. System.out.println(userInfo);
  6. }
  7. }

4.1.2解决方案二:(常用的方案

  1. <select id="getAll1" resultType="com.example.demo10.entity.UserInfo" >
  2. select id,username as name ,password,photo,createtime,updatetime,state from userinfo
  3. </select>

生成测试方法+运行结果:

  1. @Test
  2. void getAll1() {
  3. List<UserInfo> all1 = userMapper.getAll1();
  4. for (UserInfo userInfo : all1) {
  5. System.out.println(userInfo);
  6. }
  7. }

运行结果:

4.2:一对一多表查询

目标要求;我们设计了两张表,用户表和文章表,那么,我们需要利用用户表的id对应文章表的uid,并查询出文章表的所有信息和用户名称

用户表:

文章表:

在entity的目录下创建视图类和文章类。

文章类

文章视图类

将所需要两张表查询的所有信息创建一个试图类,依据要求,此类需要包括用户的姓名和文章表的所有信息。

Mapper中声明的方法:

  1. @Mapper
  2. public interface ArticleMapper {
  3. ArticleinfoView getAll(Integer id);
  4. }

XML中的配置:

  1. <mapper namespace="com.example.demo10.mapper.ArticleMapper">
  2. <select id="getAll" resultType="com.example.demo10.entity.ArticleinfoView">
  3. select a.*,u.username from articleinfo a left join userinfo u on u.id=a.uid
  4. where a.id=#{u.id}
  5. </select>
  6. </mapper>

生成测试方法+运行结果:

  1. @SpringBootTest
  2. @Transactional
  3. class ArticleMapperTest {
  4. @Autowired
  5. private ArticleMapper articleMapper;
  6. @Test
  7. void getAll() {
  8. ArticleinfoView all = articleMapper.getAll(1);
  9. System.out.println(all);
  10. }
  11. }

运行结果:

4.3:一对多查询 

实现目标:查询一个用户有多少个文章时,我们可以用一条SQL语句进行查询。

  1. <select id="getAll1" resultType="com.example.demo10.entity.ArticleinfoView">
  2. select * from articleinfo where uid=#{id};
  3. </select>

4.4:多对多查询 

针对多对多查询,可以看成是两个一对多查询。

五:动态SQL 

当我们使用普通的SQL解决不了问题时,可以采用动态SQL解决问题。有如下五个动态SQL。

5.1:<if>标签 

5.1.1:使用案例 

Mapper中声明的方法:

  1. //添加用户信息
  2. int add2(UserInfo userInfo);

XML中的配置:

  1. <insert id="add2">
  2. insert into userinfo(
  3. username,
  4. <if test="photo!=null">
  5. photo,
  6. </if>
  7. password
  8. )values (#{username},
  9. <if test="photo!=null">
  10. #{photo},
  11. </if>
  12. password=#{password})
  13. </insert>

测试方法+运行结果

  1. void add2() {
  2. UserInfo userInfo=new UserInfo();
  3. userInfo.setUsername("李四");
  4. userInfo.setPassword("12345");
  5. userInfo.setPhoto(null);
  6. int i = userMapper.add2(userInfo);
  7. System.out.println(i);
  8. }

5.2:<trim>标签

5.2.1使用案例 

Mapper中声明的方法:

  1. //添加用户信息
  2. int add3(UserInfo userInfo);

XML中的配置:

  1. <insert id="add3">
  2. insert into userinfo
  3. <trim prefix="(" suffix=")" suffixOverrides=",">
  4. <if test="username!=null">
  5. username,
  6. </if>
  7. <if test="password!=null">
  8. password,
  9. </if>
  10. <if test="photo=null">
  11. photo
  12. </if>
  13. </trim>
  14. values
  15. <trim prefix="(" suffix=")" suffixOverrides="," >
  16. <if test="username!=null">
  17. #{username},
  18. </if>
  19. <if test="password!=null">
  20. #{password},
  21. </if>
  22. <if test="photo=null">
  23. #{photo},
  24. </if>
  25. </trim>
  26. </insert>

测试方法+运行结果:

  1. @Test
  2. void add3() {
  3. UserInfo userInfo=new UserInfo();
  4. userInfo.setUsername("老六");
  5. userInfo.setPassword("123456");
  6. userInfo.setPhoto(null);
  7. int i = userMapper.add2(userInfo);
  8. System.out.println(i);
  9. }

5.3:<set>标签 

5.4:<where>标签 

<where><if> 进行组合.

如果我们将and加在第一个<if>标签下,当第二个<if>标签不成立,此时,会对整个sql产生影响,整个SQL

select * from userinfo where username=#{username} and 

上面这个语句便会报错,不符合整个SQL的语句规范。

当条件不成立时,if条件后的内容包括and也不会存在,因此会对整个sql语句产生影响。

注意and关键字要放在每个<if>语句中的库表字段赋值的前面。因为,一旦判断不成功,<where> 会把对应的and关键字去掉(还有or关键字)。

 5.4.1使用案例:

Mapper中的声明的方法:

  1. //查询用户的信息,当传入的用户,密码其中一条为空时,能不能查询到信息
  2. UserInfo getall(String username,String password);

XML中的配置:

  1. <select id="getall" resultType="com.example.demo10.entity.UserInfo">
  2. select * from userinfo
  3. <where>
  4. <if test="username!=null">
  5. username=#{username}
  6. </if>
  7. <if test="password!=null">
  8. and password=#{password}
  9. </if>
  10. </where>
  11. </select>

测试方法+运行结果:

  1. @Test
  2. void getall() {
  3. String usernmae="李明轩";
  4. String password=null;
  5. UserInfo getall = userMapper.getall(usernmae, password);
  6. System.out.println(getall);
  7. }

5.5:<foreach>标签

当我们想要根据多个id删除多个数据时,我们使用的SQL语句如下:

delete from userinfo where id in(id1,id2,id23)

那么,我们借助<foreach>可以完成操作。

 5.5.1使用案例:

Mapper中声明的方法:

  1. //根据多条id删除数据
  2. int dels(List<Integer> ids);

XML中的配置:

  1. <delete id="dels">
  2. delete from userinfo
  3. where id in
  4. <foreach collection="ids" item="id" open="(" close=")" separator=",">
  5. #{id}
  6. </foreach>
  7. </delete>

测试方法+运行结果:

  1. @Test
  2. void dels() {
  3. List<Integer> list=new ArrayList<>();
  4. list.add(6);
  5. list.add(7);
  6. int dels = userMapper.dels(list);
  7. System.out.println(dels);
  8. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/732988
推荐阅读
相关标签
  

闽ICP备14008679号