Mybatis 中的列名和属性名的映射
# 90.Mybatis 中的列名和属性名的映射
Mybatis 的查询结果,可以是基本类型,也可以是对象类型,并且我们之前都演示过了;还可以是 POJO 列表
# Java 类属性和数据库表之间的映射
之前我们使用 User 类来存储数据库返回的数据,这要求类的属性名,和数据库列名一致,例如 User 有个成员变量是 address,数据库表中,列名也是 address;
如果两者不一致,还能映射吗?答案是可以的,只不过要做一些配置。
# 改造 User 类
我们将 User 类的成员变量前,都加上 user,使其与数据库列名不一致
public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
}
2
3
4
5
6
7
这里请读者重新生成 getter 和 setter
# 改造测试类
由于 getter 和 setter 名字都改变了,测试类里调用的方法也得改名。例如 testSave 方法:
@Test
public void testSave() throws IOException {
User user = new User();
user.setUserName("mybatis saveuser");
user.setUserAddress("广州市番禺区");
user.setUserSex("男");
user.setUserBirthday(new Date());
System.out.println("保存操作之前:: " + user);
userDao.saveUser(user);
System.out.println("保存操作之前:: " + user);
session.commit();
}
2
3
4
5
6
7
8
9
10
11
12
13
# 修改 IUserDao.xml
由于我们改了列名,配置文件中涉及到列名的也需要改,例如 insert 标签:
<insert id="saveUser" parameterType="com.peterjxl.domain.User">
<selectKey keyProperty="userId" keyColumn="id" order="AFTER" resultType="int">
select last_insert_id();
</selectKey>
insert into user(username, address, sex, birthday) values (#{userName}, #{userAddress}, #{userSex}, #{userBirthday})
</insert>
2
3
4
5
6
# 查询所有的问题
我们测试查询所有:
@Test
public void helloMybatis() throws Exception{
// 5. 使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
2
3
4
5
6
7
8
可以看到只能 userName 能正常设置参数,而数据库列名里明明是 username,有一个字母 n 大小写不同,为什么还能正常获取值呢?这是因为 Windows 下,MySQL 是不区分大小写的,所以才能正常封装。
# 解决方法 1:起别名
那如何才能让 Java 类的属性,和数据库列名保持一致呢?最简单的方式:起别名
<!-- 配置查询所有用户,id要写方法名称-->
<select id="findAll" resultType="com.peterjxl.domain.User">
select
id as userId,
username as userName,
address as userAddress,
sex as userSex,
birthday as userBirthday
from user
</select>
2
3
4
5
6
7
8
9
10
再次测试查询所有,可以看到能正常设置对象的属性了:
这种方式的效率也是很高的,因为是在 SQL 语句的层面上解决;
# 解决方法 2:配置列名和 Java 属性的映射关系
我们可以在配置文件中,新增一个 resultMap 标签作为映射关心。
resultMap 的属性 id
是唯一标识,我们这里起名叫 userMap;type 表明查询的对应的实体类是哪个,写全类名;
<resultMap id="userMap" type="com.peterjxl.domain.User">
<!-- 主键字段的对应 -->
<id property="userId" column="id" />
<!-- 非主键字段的对应 -->
<result property="userName" column="userName"/>
<result property="userAddress" column="address"/>
<result property="userSex" column="sex"/>
<result property="userBirthday" column="birthday"/>
</resultMap>
2
3
4
5
6
7
8
9
然后第一个配置的是主键字段的映射;然后是其他字段的映射,property
表示 Java 类中的列名
注意,property
属性对应的就是 Java 中的属性名的,而 Java 是区分大小写,所以别写错了
然后我们在 select 标签里,就不再使用 resultType 属性了,而是 resultMap;并且也不用再写别名了
<select id="findAll" resultMap="userMap">
select * from user
</select>
2
3
再次运行测试方法,可以看到能正常执行了。
由于该种方式,少不了再解析一次 XML,因此效率比方法 1 低一点,但是开发效率高了。并且使用这种方式,我们只需改造 select 等标签的 resultMap 属性,改动较小;而使用别名的方式,改动较大。
各有利弊,按需选择
# 源码
所有代码已上传到了 GitHub (opens new window) 和 Gitee (opens new window) 上,并且创建了分支 demo9,读者可以通过切换分支来查看本文的示例代码。