首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >5. Mybatis 单表查询 - resultMap标签 - 多条件查询 - 模糊查询

5. Mybatis 单表查询 - resultMap标签 - 多条件查询 - 模糊查询

作者头像
Devops海洋的渔夫
发布2022-01-17 14:37:11
发布2022-01-17 14:37:11
1.2K0
举报
文章被收录于专栏:Devops专栏Devops专栏

5. Mybatis 单表查询 - resultMap标签 - 多条件查询 - 模糊查询

数据准备

代码语言:javascript
复制
# 数据准备

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 属性名称不一致,如下:

代码语言:javascript
复制
<!--
查询语句
id: 接口中方法的名字
resultType:返回的实体类的类型,类全名
-->
<select id="findAllUsers" resultType="user">
    -- select * from user
    select id as uid, username as uname, birthday, sex, address  from user
</select>

现在我们在测试方法再执行查询看看结果,如下:

代码语言:javascript
复制
// 使用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> 作为查询的结果。

代码语言:javascript
复制
 /*
    *   # 查询 : 查询表中所有的用户
    *       1.sql
    *           select id,username,birthday,sex,address
    *               from user
    *
    *       2.没有参数
    *       3.返回值类型: List<User>
    * */
    List<User> findAllUsers();
② UserMapper.xml

下面我们改用 resultMap 来定义查询结构集字段名 与 实体类属性名的 映射关系,从而成功读取数据。

代码语言:javascript
复制
<!--
       # 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>
③ 测试
代码语言:javascript
复制
// 使用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接口
代码语言:javascript
复制
/*
 *   # 查询: 多条件查询
 *       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
代码语言:javascript
复制
<!--  参数:name 与 sex 都已经进行了映射,所以配置文件知道参数的对应关系  -->
<select id="findUsersByNameAndSex" resultType="user">
       select *  from user where username = #{name} and sex = #{sex}
</select>
③ 测试
代码语言:javascript
复制
// 测试多条件查询
@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接口
代码语言:javascript
复制
// 方案二: 把这些参数都封装一个javabean中
List<User> findUsersByNameAndSex2(User user);
② UserMapper.xml
代码语言:javascript
复制
<!--  参数:由于传入的是 user 对象作为参数,此时填写 #{参数名} 需要时 user 对象的属性名 -->
<select id="findUsersByNameAndSex2" resultType="user">
       select *  from user where username = #{username} and sex = #{sex}
</select>
③ 测试
代码语言:javascript
复制
@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接口
代码语言:javascript
复制
/*
 * # 模糊查询
 *   sql :
 *       select * from user where username like ?
 *   参数:
 *       keyword = 白  , 拼接之后: %白%
 *   返回值:  List<User>
 * */
List<User> findUsersByKd(String keyword);
② UserMapper.xml
代码语言:javascript
复制
<!--
     模糊查询
     方案一: 不推荐, 耦合严重
 -->
<select id="findUsersByKd" resultType="user">
       select * from user where username like #{keyword}
</select>
③ 测试
代码语言:javascript
复制
// 模糊查询:方案一
@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
代码语言:javascript
复制
<!--
   模糊查询,方式二【了解】
       mysql5.5版本之前,此拼接不支持多个单引号
       oracle数据库,除了别名的位置,其余位置都不能使用双引号
-->
<select id="findUsersByKd" resultType="User">
    select * from user where username like '%' #{keyword} '%'
</select>
③ 测试
代码语言:javascript
复制
    @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
代码语言:javascript
复制
<!--
模糊查询,方式三【此方式,会出现sql注入...】
    ${} 字符串拼接,如果接收的简单数据类型,表达式名称必须是value
-->
<select id="findUsersByKd"  resultType="User">
    select * from user where username like '%${value}%'
</select>
③ 测试
代码语言:javascript
复制
    @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
代码语言:javascript
复制
<!--
模糊查询,方式四【掌握】
    使用concat()函数拼接  : mysql函数可以多参数
    注意:oracle数据库 concat()函数只能传递二个参数...  可以使用函数嵌套来解决
        concat(concat('%',#{username}),'%');
-->
<select id="findUsersByKd"  resultType="User">
  select * from user where username like concat('%',#{username},'%')
</select>
③ 测试
代码语言:javascript
复制
    @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

  1. sql与参数拼接在一起,会出现sql注入问题
  2. 每次执行sql语句都会编译一次

#{}:底层 PreparedStatement

  1. sql与参数分离,不会出现sql注入问题
  2. sql只需要编译一次
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 海洋的渔夫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 5. Mybatis 单表查询 - resultMap标签 - 多条件查询 - 模糊查询
    • 数据准备
    • resultMap标签
      • 如果数据库返回结果的列名和要封装的实体的属性名完全一致的话用 resultType 属性
      • 如果数据库返回结果的列名和要封装的实体的属性名有不一致的情况用 resultMap 属性
    • 多条件查询_参数映射
      • 方案一:将多条件查询的参数都进行传参,此时多个参数就需要设置参数映射
      • 方案二:将多条件查询的参数都封装到一个javabean的实体类 user 对象中,这样就只需要传递一个参数,那么就不需要进行参数映射
    • 模糊查询
      • 方案一:在调用查询方法的位置直接传递 %username% 作为查询参数(不推荐,耦合严重)
      • 方案二:在接口映射文件拼接查询参数 '%' #{keyword} '%' (不推荐,mysql5.5版本之前,此拼接不支持多个单引号)
      • 方案三:在接口映射文件使用 ${} 字符串拼接 (不推荐,存在SQL注入的风险)
      • 方案四:在接口映射文件使用concat()函数拼接查询参数(推荐)
    • ${} 与 #{} 区别
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档