MyBatis查询操作
大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流
作者简介:
- CSDN java领域新星创作者blog.csdn.net/bug…
- 掘金LV3用户 juejin.cn/user/bug…
- 阿里云社区专家博主,星级博主,developer.aliyun.com/bug…
- 华为云云享专家 bbs.huaweicloud.com/bug…
查询操作
刚刚的只是简单的查询操作!
而我们的查询操作往往是要多个表一起,是十分复杂的!
参数 #{} 和 ${}区别
#{}
: 预编译处理${}
:字符直接替换
预编译处理指的是MyBatis在处理#{}时,会将SQL中的#{} 替换成?号,使用
PreparedStatement
来赋值
直接替换:就是在Mybatis处理${}替换成变量的值!
预编译处理和字符串替换的区别故事(头等舱和经济舱乘机分离的故事)
预处理就好使头等舱乘客先登机,然后关闭头等舱,后面才是经济舱乘客登机,这样经济舱就去不了头等舱,而直接替换就是头等舱和经济舱一起登机,云龙混杂,很可能经济舱用户来到头等舱!
参数直接替换,它的问题是可能会带来越权查询和操作数据等问题,比如面会讲的 SQL 注入问题
${}
优点
如果我们传入某个sql
时,通过直接替换即可!而预编译就会解析成字符串,会自动加上引号,就不行了!
select * from userinfo order by id ${sort}
使用${sort}
可以实现排序查询,而使用#{sort}
就不能实现排序查询了,因为当使用 #{sort}
查询时,如果传递的值为String
则会加单引号,就会导致 sql
错误。
SQL注入问题
<select id="isLogin" resultType="com.example.demo.model.User">
select * from userinfo where username='${name}' and password='${pwd}'
</select>
@RequestMapping("/isLogin")
public User isLogin(@RequestParam String name,@RequestParam String password){
return userService.isLogin(name,password);
}
当我们密码传入为'or 1=1 and id = '2
时!
我们居然查询成功了!
因为这里是直接替换,我们将SQL替换一下就会发现问题所在!
替换后的SQL语句变成了如下:
select * from where username = 'admin' and password = ''or 1=1 and id = '2'
这样就阴差阳错的查询到了id=2
的用户信息!
查询尽量用#{}
Like 查询
like
使用#{}
报错
<select id="findUserByName3" resultType="com.example.demo.model.User">
select * from userinfo where username like '%#{username}%'
</select>
预编译后SQL变成如下:
select * from userinfo where username like '%'usernane'%'
;
这个又不能直接使用${}
的!所以考虑MySQL下的内置函数concat()
处理!
select id="findUserByName3" resultType="com.example.demo.model.User">
select * from userinfo where username like concat('%',#{username},'%');
</select>
多表查询
我们知道当我们进行增删改操作的时候,结果是返回受影响的行数,所以可以不设置返回值!
而进行查询操作一定要设置返回的类型,否则会报错!因为我们查询的结果一般都是含有多列是一组对象集合!
返回类型reslutType
在通常情况下,我们返回类型通过
ResultType
设置即可!
<select id="getAll" resultType="com.example.demo.model.User">
select * from userinfo
</select>
优点使用方便直接定义到某个实体类即可!
返回类型resultMap
使用场景:
- 字段名称和程序中的属性名称不同,可使用resultMap进行映射!
- 一对一或一对多关系可以使用resultMap映射并且查询数据
字段名和属性名不同
我们通过resultType
进行查询操作时
因为我们程序中的字段和数据库中的字段信息不匹配所以数据库中的password
无法映射到对象pwd
属性!
通过resultMap实行映射
我们先给程序中的类和数据库中表建立映射关系!通过xml
配置文件进行配置即可
<resultMap id="baseMap" type="com.example.demo.model.User">
<id column="id" property="id"></id>
<id column="username" property="username"></id>
<id column="password" property="pwd"></id>
</resultMap>
<select id="getAll" resultMap="com.example.demo.mapper.UserMapper.baseMap">
select * from userinfo
</select>
resultMap
中的id
:是映射关系标识,等下进行查询如果要使用这个映射关系就需要用到这个标识!type
:我们需要映射的类!column
中的id
:这里是数据库中的字段名!property
:类中的属性名! 通过这样一一映射,就整张表映射起来了,名称一样可以不进行映射!- 然后我们在查询的
resultMap
返回刚刚的映射标识所在的位置即可!
注意这里baseMap
的位置是我们要实现的接口位置,然后加上标识!
然后验证结果
一对一映射
假如我们需要通过用户信息查询该用户的文章信息!
这里就要进行2张表的联系!
这是这些表的信息!如果我们要通过用户信息表查询到文章表!
直接查询是获取不到结果的!
例如下面的文章类
这里有一个属性是User
类! 如果我们直接单表查询文章表,肯定查询不到User类型的值!所以我们要通过resultMap
进行映射处理!
package com.example.demo.model;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class ArticleInfo {
int id;
String title;
String content;
LocalDateTime createtime;
LocalDateTime updatetime;
int uid;
int rcount;
int state;
User user;
}
将ArticleInfo
和表进行映射!
<resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">
<id property="id" column="id"></id>
<result property="title" column="title"></result>
<result property="content" column="content"></result>
<result property="createtime" column="createtime"></result>
<result property="updatetime" column="updatetime"></result>
<result property="uid" column="uid"></result>
<result property="rcount" column="rcount"></result>
<result property="state" column="state"></result>
<association property="user"
resultMap="com.example.demo.mapper.UserMapper.baseMap"
columnPrefix="u_">
</association>
</resultMap>
<select id="getAll" resultMap="BaseMap">
select a.*,u.username u_username from articleinfo a
left join userinfo u on a.uid=u.id
</select>
这里唯一的不同就是:
<association>
:实现user
和表的映射!
property
:是当前表的属性值
resultMap
:需要映射到的映射标识,因为我们已经映射了User
表!
columnPrefix
:为User查询的信息添加前缀,为了区分当前的ArticleInfo
有同名的字段,绑定一对一对象时,是通过columnPrefix+assocation.resultMap.column
来映射结果集字符的,这里assocation.resultMap.column是指<association>
标签中的resultMap属性,对应的映射中,columnPrefix
不能省略!
进行查询验证结果!
一对多映射
一对多映射也是需要使用
<collection>
标签!用法和<association>
类似!
<resultMap id="Base" type="com.example.demo.model.User">
<id property="id" column="id"></id>
<id property="username" column="usename"></id>
<id property="pwd" column="password"></id>
<id property="photo" column="photo"></id>
<collection property="users" resultMap="com.example.demo.mapper.UserMapper.BaseMap"
columnPrefix="a_">
</collection>
</resultMap>
<select id="getUserById" resultMap="Base">
select u.*,a.title a_title from userinfo u left join articleinfo a on
u.id = a.uid where u.id = #{id}
</select>
验证结果:
- 点赞
- 收藏
- 关注作者
评论(0)