5. Mybatis 单表查询 – resultMap标签 – 多条件查询 – 模糊查询
数据准备
# 数据准备
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` varchar(10) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2019-05-27 17:47:08','男','北京'),(42,'王小二','2019-03-02 15:09:37','女','北京金燕龙'),(43,'老李','2019-03-04 11:34:34','女','北京修正'),(45,'传智播客','2019-03-04 12:04:06','男','北京金燕龙'),(46,'王小二','2018-09-07 17:37:26','男','北京TBD'),(48,'小马宝莉','2019-03-08 11:44:00','女','北京修正');
resultMap标签
-
如果数据库返回结果的列名和要封装的实体的属性名完全一致的话用 resultType 属性
-
如果数据库返回结果的列名和要封装的实体的属性名有不一致的情况用 resultMap 属性
-
使用resultMap手动建立对象关系映射。
如果数据库返回结果的列名和要封装的实体的属性名完全一致的话用 resultType 属性
在前面篇章中,我们编写查询的都是 select * from user
这样的查询,而查询的结果集字段名 都是对应 我们编写的实体类 User 相关属性名。所以我们设置返回的结果都是用 resultType
属性,如下:
但是如果查询的结果集字段名 与 实体类User 属性名称不一致的话,那样就会导致获取不到参数的情况。
我们可以在UserMapper.xml
修改一下查询的字段,使其与实体类 User 属性名称不一致,如下:
<!--
查询语句
id: 接口中方法的名字
resultType:返回的实体类的类型,类全名
-->
<select id="findAllUsers" resultType="user">
-- select * from user
select id as uid, username as uname, birthday, sex, address from user
</select>
现在我们在测试方法再执行查询看看结果,如下:
// 使用MyBatisUtil工具类
@Test
public void test07() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allUsers = mapper.findAllUsers();
for (User user : allUsers) {
System.out.println(user);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
那么假设我们就是需要将查询的字段设置别名,那么我们该怎么做呢?下面来看看 resultMap 属性。
如果数据库返回结果的列名和要封装的实体的属性名有不一致的情况用 resultMap 属性
① UserMapper接口
查询接口方法不需要改变,还是照样接收 List<User>
作为查询的结果。
/*
* # 查询 : 查询表中所有的用户
* 1.sql
* select id,username,birthday,sex,address
* from user
*
* 2.没有参数
* 3.返回值类型: List<User>
* */
List<User> findAllUsers();
② UserMapper.xml
下面我们改用 resultMap 来定义查询结构集字段名 与 实体类属性名的 映射关系,从而成功读取数据。
<!--
# resultMap 标签 : 设置结果集映射到某个对象中
1. 属性
id : resultMap的id(唯一性)
type : resultMap的类型
2. 子标签
id子标签: 设置主键映射 (不论是否一致,必须要写)
result子标签: 非主键映射(如果一致,可以不写,推荐写)
3. 子标签属性
property : resultMap类型中的属性名
column : sql结果集的列名(字段名)
-->
<resultMap id="userResult" type="user">
<id property="id" column="uid"/>
<result property="username" column="uname"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</resultMap>
<!-- 返回值类型: userResult-->
<select id="findAllUsers" resultMap="userResult">
select id as uid, username as uname, birthday, sex, address from user
</select>
③ 测试
// 使用MyBatisUtil工具类
@Test
public void test07() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allUsers = mapper.findAllUsers();
for (User user : allUsers) {
System.out.println(user);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
多条件查询_参数映射
需求
根据id和username查询user表。
在前面的案例中,我们只进行了单条件查询,而如果存在多条件查询的话,在参数设置的时候也会特殊处理一下。
而多条件查询具有两种解决方案:
-
方案一:将多条件查询的参数都进行传参,此时多个参数就需要设置参数映射 -
方案二:将多条件查询的参数都封装到一个javabean的实体类 user 对象中,这样就只需要传递一个参数,那么就不需要进行参数映射
下面我们来逐个实现一下:
方案一:将多条件查询的参数都进行传参,此时多个参数就需要设置参数映射
① UserMapper接口
/*
* # 查询: 多条件查询
* 1. sql
* select * from user where username = ? and sex = ?
*
* 2. 参数
* String , String
*
* 3. 返回值类型: List<User>
*
* 接口和映射文件(参数映射)
* 1. 如果只有一个参数,可以不用写参数映射
* 2. 如果有2个以及以上,必须要写参数映射 -> 如果没写,则会报异常:BindException
* @Param("name") String name : 相当于告诉mybatis映射文件,这个属性是name
*
* */
//方案一: 参数列举出来
List<User> findUsersByNameAndSex(@Param("name") String name, @Param("sex")String sex);
② UserMapper.xml
<!-- 参数:name 与 sex 都已经进行了映射,所以配置文件知道参数的对应关系 -->
<select id="findUsersByNameAndSex" resultType="user">
select * from user where username = #{name} and sex = #{sex}
</select>
③ 测试
// 测试多条件查询
@Test
public void test08() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.findUsersByNameAndSex("李小白", "男");
for (User user : users) {
System.out.println(user);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
在这里我们已经实现了多条件查询的操作,下面我们再来看看方案二。
方案二:将多条件查询的参数都封装到一个javabean的实体类 user 对象中,这样就只需要传递一个参数,那么就不需要进行参数映射
① UserMapper接口
// 方案二: 把这些参数都封装一个javabean中
List<User> findUsersByNameAndSex2(User user);
② UserMapper.xml
<!-- 参数:由于传入的是 user 对象作为参数,此时填写 #{参数名} 需要时 user 对象的属性名 -->
<select id="findUsersByNameAndSex2" resultType="user">
select * from user where username = #{username} and sex = #{sex}
</select>
③ 测试
@Test
public void test09() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 2.1 封装查询参数到user对象
User user = new User();
user.setUsername("杜甫");
user.setSex("男");
// 2.2 传入user对象进行查询
List<User> list = mapper.findUsersByNameAndSex2(user);
for (User item : list) {
System.out.println(item);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
模糊查询
需求
根据username模糊查询user表。
方案一:在调用查询方法的位置直接传递 %username%
作为查询参数(不推荐,耦合严重)
① UserMapper接口
/*
* # 模糊查询
* sql :
* select * from user where username like ?
* 参数:
* keyword = 白 , 拼接之后: %白%
* 返回值: List<User>
* */
List<User> findUsersByKd(String keyword);
② UserMapper.xml
<!--
模糊查询
方案一: 不推荐, 耦合严重
-->
<select id="findUsersByKd" resultType="user">
select * from user where username like #{keyword}
</select>
③ 测试
// 模糊查询:方案一
@Test
public void test10() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//方案一: 耦合度太高(java程序写sql语法)
List<User> list = mapper.findUsersByKd("%白%");
for (User item : list) {
System.out.println(item);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
可以看到上面的示例中,我们在 java 代码里面设置关键字查询参数需要写成 %白%
,这样就导致 java代码 与 sql代码 之间的 耦合性比较高。
最好的方式就是 java 代码不需要写 %
这样的 sql 代码。
方案二:在接口映射文件拼接查询参数 '%' #{keyword} '%'
(不推荐,mysql5.5版本之前,此拼接不支持多个单引号)
① UserMapper接口
不需要改变。
② UserMapper.xml
<!--
模糊查询,方式二【了解】
mysql5.5版本之前,此拼接不支持多个单引号
oracle数据库,除了别名的位置,其余位置都不能使用双引号
-->
<select id="findUsersByKd" resultType="User">
select * from user where username like '%' #{keyword} '%'
</select>
③ 测试
@Test
public void test10() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//方案二:在接口映射文件拼接查询参数 `'%' #{keyword} '%'` (不推荐,mysql5.5版本之前,此拼接不支持多个单引号)
List<User> list = mapper.findUsersByKd("白");
for (User item : list) {
System.out.println(item);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
方案三:在接口映射文件使用 ${} 字符串拼接
(不推荐,存在SQL注入的风险)
① UserMapper接口
不需要改变。
② UserMapper.xml
<!--
模糊查询,方式三【此方式,会出现sql注入...】
${} 字符串拼接,如果接收的简单数据类型,表达式名称必须是value
-->
<select id="findUsersByKd" resultType="User">
select * from user where username like '%${value}%'
</select>
③ 测试
@Test
public void test10() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 方案三:在接口映射文件使用 `${} 字符串拼接` (不推荐,存在SQL注入的风险)
List<User> list = mapper.findUsersByKd("白");
for (User item : list) {
System.out.println("方案三: " + item);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
方案四:在接口映射文件使用concat()函数拼接查询参数(推荐)
① UserMapper接口
不需要改变。
② UserMapper.xml
<!--
模糊查询,方式四【掌握】
使用concat()函数拼接 : mysql函数可以多参数
注意:oracle数据库 concat()函数只能传递二个参数... 可以使用函数嵌套来解决
concat(concat('%',#{username}),'%');
-->
<select id="findUsersByKd" resultType="User">
select * from user where username like concat('%',#{username},'%')
</select>
③ 测试
@Test
public void test10() throws IOException {
// 1. 获取 sqlSession 数据库连接会话
MyBatisUtil myBatisUtil = new MyBatisUtil();
SqlSession sqlSession = myBatisUtil.getSqlSession();
// 2. 执行查询操作
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 方案四:在接口映射文件使用concat()函数拼接查询参数(推荐)
List<User> list = mapper.findUsersByKd("白");
for (User item : list) {
System.out.println("方案四: " + item);
}
// 3. 关闭会话
myBatisUtil.commitAndClose(sqlSession);
}
${} 与 #{} 区别
${}
:底层 Statement
-
sql与参数拼接在一起,会出现sql注入问题 -
每次执行sql语句都会编译一次
#{}
:底层 PreparedStatement
-
sql与参数分离,不会出现sql注入问题 -
sql只需要编译一次
原文始发于微信公众号(海洋的渔夫):5. Mybatis 单表查询 – resultMap标签 – 多条件查询 – 模糊查询
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/33716.html