目录
Mybatis的参数
一、parameterType配置参数
1. 引入
我们在对SQL语句传递参数的时候,使用标签的parameterType属性
来设定。该属性的取值可以是基本类型,引用类型(例如String类型),还可以是实体类类型(POJO类型),同时也可以使用实体类的包装类,我们将着重介绍如何使用实体类的包装类作为参数传递。
2. 注意事项
- 基本类型和String类型我们可以直接写类型名称,也可以使用包名.类名的方式,例如:
java.lang.String
。 - 而实体类类型,我们只能写全限定类名。
其中的原因呢,就是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名, 而我们的是实体类并没有注册别名,所以必须写全限定类名。而如何注册实体类的别名我们后面再讲。
在mybatis的官方文档说明中:
这些都是支持的默认别名。
如果我们打开源码 TypeAliasRegistery.class
,我们可以清楚地看出它们分别是怎么定义出来的:
3. 传递poji包装对象
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
我们举一个例子:
需求: 根据用户查询用户信息,查询条件放到QueryVo的user属性中。
①编写QueryVo
package com.veeja.domain;
/**
* 查询条件对象。
*/
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
②编写持久层接口
/**
* @author veeja
* <p>
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 根据QueryVo中的条件查询用户
*
* @param vo
* @return
*/
List<User> findUserByVo(QueryVo vo);
}
③持久层接口的映射文件
<!--根据queryVo的条件查询用户-->
<select id="findUserByVo" parameterType="com.veeja.domain.QueryVo"
resultType="com.veeja.domain.User">
select * from user where username like #{user.username}
</select>
④测试包装类作为参数
/**
* 测试使用QueryVo作为查询条件
*/
@Test
public void testFindByVo() throws IOException {
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%李%");
vo.setUser(user);
// 执行删除方法
List<User> users = userDao.findUserByVo(vo);
for (User u : users) {
System.out.println(u);
}
}
⑤运行结果
也完全符合我们的预期。
二、Mybatis的输出结果封装
resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。
我们在前面的 CRUD 案例中已经对此属性进行过应用了。
需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须 使用全限定类名。例如:我们的实体类此时必须是全限定类名(今天最后一个章节会讲解如何配置实体类的别名)
同时,当是实体类名称是,还有一个要求,实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。
1. 基本类型示例
这一种我们在CRUD操作中已经使用过了。就不再赘述,只是把例子放在下面:
① Dao接口
/**
* 查询用户的总记录数
*
* @return
*/
int findTotal();
② 映射配置
<!--查询用户的总记录数-->
<select id="findTotal" resultType="int">
select count(id) from user
</select>
2. 实体类类型示例
这一种我们在CRUD操作中已经使用过了。就不再赘述,只是把例子放在下面:
① Dao接口
/**
* 查询所有的用户
*
* @return
*/
List<User> findAll();
② 映射配置
<!-- 查询所有的操作 -->
<select id="findAll" resultType="com.veeja.domain.User">
select * from user
</select>
3. 特殊情况示例
① 修改实体类
如果我们修改实体类中的属性名称,让实体类中的属性和数据库中的列名不一致,例如修改User类:
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;
}
......
......
......
......
}
其实就是简单的修改实体类中属性名称,并且重新生成get/set方法和toString方法。
② Dao接口
/**
* 查询所有的用户
*
* @return
*/
List<User> findAll();
③ 映射配置
<!-- 查询所有的操作 -->
<select id="findAll" resultType="com.veeja.domain.User">
select * from user
</select>
④ 测试查询结果
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
// 5. 执行查询所有方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
我们运行一下,发现出现问题了:
我们发现,大部分都是null,而只有username显示了属性。
null的原因是我们修改了实体类的属性名,就没法映射过来了。而username有值的原因是我们是把username修改为了userName,而MySQL在windows系统中是不区分大小写的。所以才会有这种现象。
⑤ 修改映射配置
针对上面的问题我们应该怎么解决呢?
其中一个方案是我们可以使用别名进行查询,例如把映射配置文件修改为:
<!-- 查询所有的操作 -->
<select id="findAll" resultType="com.veeja.domain.User">
select id as userId,username as userName,birthday as userBirthday,
sex as userSex, address as userAddress from user
</select>
查询结果:
如果我们查询的表中列很多,都使用别名的话岂不是很麻烦,有没有别的解决办法呢?
请往下看。
4. resultMap结果类型
resultMap标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系,从而实现封装。
在select标签中使用resultMap属性指定引用即可。同时resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
那么我们怎么样解决上面遗留的问题呢?
① 定义resultMap
我们要在resultMap中建立User实体类和数据库表的对应关系。
使用type属性来指定实体类的全限定类名。
id属性是给定的一个唯一标识,是给查询select标签引用使用的。
在IUserDao.xml中添加:
<!--配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="userMap" type="com.veeja.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>
②查询操作的配置
而我们的查询配置,指定的resultType属性要更换成resultMap属性,换成我们上面声明的id即可,也就是:
<!-- 查询所有的操作 -->
<select id="findAll" resultMap="userMap">
<!--select id as userId,username as userName,birthday as userBirthday, sex as userSex, address as userAddress from user-->
select * from user
</select>
③测试查询
我们再次执行查询的方法,发现是没有问题的:
end.