Mybatis 框架学习4 - Mybatis的参数

31 篇文章 0 订阅
18 篇文章 0 订阅

1. Mybatis 的参数

1.1 parameterType (输入类型)

1.1.1 传递简单参数

​ 基本类型和 String 我们可以直接写类型名称,可以使用包名.类名的方式,例如:java.lang.String。

1.1.2 传递 POJO 对象

​ 对于实体类类型,目前我们只能使用全限定名称。

​ Mybatis 使用 ognl 表达式解析对象字段的值,#{} 或者 ¥{} 括号中为的值为 pojo 属性名称

OGNL表达式:

​ 是由 Apache 开发的,全称是 Object Graphic Navigation Language(对象图导航语言)。它是通过对象的取值方法来获取数据,在写法上把get省略了。

​ 比如我们获取用户的名称:

​ 类中的写法:user.getUsername();

​ OGNL表达式写法:user.username

​ Mybaits 中为什么能直接写 username, 而不用user. 呢?

​ 因为在 parameterType 中已经提供了这个属性所属的类,所以此时不需要写对象名,而是直接写属性名。

1.1.3 传递 POJO 包装对象

​ 开发中通过 pojo 查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其他的查询条件 (比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传入输入参数,pojo 类中包含 pojo。

​ 这个方法也经常用于开发中,由多个对象组成查询条件,然后进行查询

​ 那么这个传递 POJO 包装对象到底应该怎么使用呢?

​ 以下是一个例子:

1.4.1 例子 - 该例子的前置条件在 完成CRUD一章有

  1. 首先我们要在 dao 类中写入一个方法:

        /**
         * 根据 queryVo 中的条件查询用户
         * @param vo
         * @return
         */
        List<User> findByVo(QueryVo vo);
    
  2. 接着创建一个 POJO 类,这个 POJO 和其他的 POJO 没有什么不同,只不过,它其中封装或者说包装了一个 POJO 对象:

    package com.itheima.domain;
    
    public class QueryVo {
    
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    }
    
  3. 然后配置映射文件

    <!--    根据QueryVo 的条件查询用户-->
        <select id="findByVo" parameterType="com.itheima.domain.QueryVo" resultType="com.itheima.domain.User">
            select * from user where username like #{user.username};
        </select>
    
  4. 在测试文件写入以下测试方法:

    @Test
        public void testFindByVo() {
            QueryVo vo = new QueryVo();
            User user = new User();
            user.setUsername("%王%");
            vo.setUser(user);
            // 执行查询一个方法
            List<User> users = userDao.findByVo(vo);
            for(User u : users) {
                System.out.println(user);
            }
            sqlSession.commit();
        }
    
    
  5. 以下是执行结果:

    2019-08-22 19:27:55,480 0      [           main] DEBUG ache.ibatis.logging.LogFactory  - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
    2019-08-22 19:27:55,509 29     [           main] DEBUG source.pooled.PooledDataSource  - PooledDataSource forcefully closed/removed all connections.
    2019-08-22 19:27:55,509 29     [           main] DEBUG source.pooled.PooledDataSource  - PooledDataSource forcefully closed/removed all connections.
    2019-08-22 19:27:55,509 29     [           main] DEBUG source.pooled.PooledDataSource  - PooledDataSource forcefully closed/removed all connections.
    2019-08-22 19:27:55,510 30     [           main] DEBUG source.pooled.PooledDataSource  - PooledDataSource forcefully closed/removed all connections.
    2019-08-22 19:27:55,593 113    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Opening JDBC Connection
    2019-08-22 19:27:56,699 1219   [           main] DEBUG source.pooled.PooledDataSource  - Created connection 391630194.
    2019-08-22 19:27:56,700 1220   [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1757cd72]
    2019-08-22 19:27:56,704 1224   [           main] DEBUG .itheima.dao.IUserDao.findByVo  - ==>  Preparing: select * from user where username like ?; 
    2019-08-22 19:27:56,734 1254   [           main] DEBUG .itheima.dao.IUserDao.findByVo  - ==> Parameters: %王%(String)
    2019-08-22 19:27:56,763 1283   [           main] DEBUG .itheima.dao.IUserDao.findByVo  - <==      Total: 4
    User{id=41, username='老王', address='北京', sex='男', birthday=Tue Feb 27 17:47:08 CST 2018}
    User{id=42, username='小二王', address='北京金燕龙', sex='女', birthday=Fri Mar 02 15:09:37 CST 2018}
    User{id=43, username='小二王', address='北京金燕龙', sex='女', birthday=Sun Mar 04 11:34:34 CST 2018}
    User{id=46, username='老王', address='北京', sex='男', birthday=Wed Mar 07 17:37:26 CST 2018}
    2019-08-22 19:27:56,765 1285   [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1757cd72]
    2019-08-22 19:27:56,765 1285   [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1757cd72]
    2019-08-22 19:27:56,765 1285   [           main] DEBUG source.pooled.PooledDataSource  - Returned connection 391630194 to pool.
    

2. Mybatis 输出结果封装

2.1 resultType 配置结果类型

​ reusltType 属性可以指定结果集的类型,他支持基本类型和实体类类型。

​ 我们在前面的 CRUD 案例中已经对此属性进行过应用了。

​ 需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名。例如:我们的实体类此时必须是全限定类名

​ 同时,当然是实体类名称时,还有一个要求,实体类中的属性名称必须和查询语句中的类名保持一致,否则无法实现封装。

2.1.1 基本类型实例

  1. 在 dao 接口中 :

    int CountUsers(); // 查询所有结果
    
  2. 映射文件配置:

    <select id="CountUsers" resultType="int">
    	select count(id) from user;
    </select>
    

2.1.2 实体类类型实例

  1. 在 dao 接口中:

    List<User> findAll(); // 查询所有
    
  2. 映射文件中:

    <select id="findAll" resultType="com.domain.User">
    	select * from user;
    </select>
    

2.1.3 特殊情况实例

  1. 修改实体类

    我们将实体类修改成这个样子:

    package com.itheima.domain;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class User implements Serializable {
        private Integer userId;
        private String userName;
        private String userAddress;
        private String userSex;
        private Date userBirthday;
    
        @Override
        public String toString() {
            return "User{" +
                    "userId=" + userId +
                    ", username='" + userName + '\'' +
                    ", userAddress='" + userAddress + '\'' +
                    ", userSex='" + userSex + '\'' +
                    ", userBirthday=" + userBirthday +
                    '}';
        }
    
        public Integer getUserId() {
            return userId;
        }
    
        public void setUserId(Integer userId) {
            this.userId = userId;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getUserAddress() {
            return userAddress;
        }
    
        public void setUserAddress(String userAddress) {
            this.userAddress = userAddress;
        }
    
        public String getUserSex() {
            return userSex;
        }
    
        public void setUserSex(String userSex) {
            this.userSex = userSex;
        }
    
        public Date getUserBirthday() {
            return userBirthday;
        }
    
        public void setUserBirthday(Date userBirthday) {
            this.userBirthday = userBirthday;
        }
    }
    

    此时,实体类已经和我们之前的使用的实体类不一样了。

  2. 然后,我们需要将映射文件中的部分内容进行修改:

    1. 首先: 获取 插入数据的id 这一个操作中的

      keyProperty = "id"
      

      由于我们已经修改了实体类,实体类中已经没有 id 这一个属性类了,就会报错

      将其修改为:

      keyProperty = "userId"
      
    2. 其次,当 sql 语句中的

      (#{username}, #{address}, #{sex}, #{birthday});
      

      values 开始寻找 OGNL 表达式,当 OGNL 表达式找不到对应的属性名称,也会报错。

      将其修改为:

      (#{userName}, #{userAddress}, #{userSex}, #{userBirthday});
      
  3. 因为 Mybatis 需要我们实体类中的 属性名称和数据库中的属性名相同,当我们修改了实体类之后,它们之间不能一一对应,所以出现了以下的情况:

    User{userId=null, username='老王', userAddress='null', userSex='null', userBirthday=null}
    User{userId=null, username='小二王', userAddress='null', userSex='null', userBirthday=null}
    User{userId=null, username='小二王', userAddress='null', userSex='null', userBirthday=null}
    User{userId=null, username='传智播客', userAddress='null', userSex='null', userBirthday=null}
    User{userId=null, username='老王', userAddress='null', userSex='null', userBirthday=null}
    User{userId=null, username='小马宝莉', userAddress='null', userSex='null', userBirthday=null}
    User{userId=null, username='mybatis update user1', userAddress='null', userSex='null', userBirthday=null}
    User{userId=null, username='mybatis save user and get id', userAddress='null', userSex='null', userBirthday=null}
    

    至于为什么会有 username 的结果,这是因为,在 windows 中的 mysql 的列名不分大小写。在这里需要注意的是,在 Linux 操作系统下,mysql 数据库是严格区分大小的。这个时候连 username 都封装不进去。

    当然解决这些问题最直接的方法,当时直接给属性起别名:

    select id as userId, username as userName, address as userAddress, birthday as userBirthday, sex as userSex from user;
    

    当我们起好别名以后,这样,我们的属性名和列名就一致了。

    起别名这种方式,一定是可以的,同时这种方式也是效率最高的,因为这是在 SQL 层面上解决问题。

    当然,Mybatis 框架也提供了一个 resultMap 结果类型,采用配置的方式,解决这个问题。

2.2 resultMap 结果类型

​ resultMap 标签可以建立查询的列名和实体类的属性名不一致时建立对应关系。从而实现封装。

​ 在 select 标签中使用 resultMap 属性指引引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。

2.2.1 定义 resultMap
<!-- 建立 User 实体和数据库表的对应关系
	type 属性:指定实体类的全限定类名
	id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
-->
<resultMap id="userMap" type="com.itheima.domain.User">
<!--        主字段的对应 -->
        <id property="userId" column="id"></id>
<!--        非主键字段的对应-->
        <result property="userName" column="username"></result>
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
</resultMap>

同时我们必须修改查询所有这段映射文件配置的内容,以使用 resultMap:

<!--    查询所有操作-->
    <select id="findAll" resultMap="userMap">
        <!--select id as userId, username as userName, address as userAddress, sex as userSex, birthday as userBirthday from user; -->
        select * from user;
    </select>

由于在程序的运行时,必须多解析一段 xml 语句,所以效率不及直接使用sql语句,但是,带来的好处是开发的效率大大地提高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值