Mybatis学习笔记_6、Mybatis关联映射

结果映射

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份
resultMap 能够代替实现同等功能的数千行代码。ResultMap
的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

之前已经使用过简单映射语句的示例,它们没有显式指定 resultMap。比如:

<select id="selectUserById" parameterType="Integer"
resultType="user">
	select * from t_user where u_id = #{id}
</select>

上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为领域模型。MyBatis 对两者都提供了支持。看看下面这个 JavaBean:

package pers.goodwin.mybatis.bean;

/**
 * @author goodwin
 *
 */
public class User {
	private Integer  id;
	private String  username;
	private String  password;
	private Integer  gender;
	private Integer  cid;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Integer getGender() {
		return gender;
	}
	public void setGender(Integer gender) {
		this.gender = gender;
	}
	public Integer getCid() {
		return cid;
	}
	public void setCid(Integer cid) {
		this.cid = cid;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + ", gender=" + gender + ", cid="
				+ cid + "]";
	}
	
	
}

基于 JavaBean 的规范,上面这个类有 5个属性:id ,username, password,gender 和cid。这些属性会对应到 select 语句中的列名。

这样的一个 JavaBean 可以被映射到 ResultSet,就像映射到 HashMap 一样简单。

<select id="selectUserById" parameterType="Integer"
	resultType="user">
	select * from t_user where u_id = #{id}
</select>

类型别名是你的好帮手。使用它们,你就可以不用输入类的全限定名了。比如:

<!-- sqlMapConfig.xml 中 -->
<typeAliases>
	<!-- <typeAlias alias="user" type="pers.goodwin.mybatis.bean.User"/> -->

	<!-- 推荐使用扫描包的形式来配置别名 包的形式会扫描包及子包下的所有文件, 以对象类名为别名,大小写不敏感,推荐使用小写 -->
	<package name="pers.goodwin.mybatis.bean" />
</typeAliases>

<!-- SQL 映射 XML 中 -->
<select id="selectUserById" parameterType="Integer"
	resultType="user">
	select * from t_user where u_id = #{id}
</select>

在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。比如:

<select id="selectUsers" resultType="User">
	select
	u_id		as "id",
	u_username	as "userName"
	from t_user
	where u_id = #{id}
</select>

在这里插入图片描述

你会发现上面的例子没有一个需要显式配置 ResultMap,这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。 虽然上面的例子不用显式配置 ResultMap。 但为了讲解,我们来看看如果在刚刚的示例中,显式使用外部的 resultMap 会怎样,这也是解决列名不匹配的另外一种方式。

<resultMap id="userResultMap" type="User">
	 <id property="id" column="u_id" />
	 <result property="username" column="u_username"/>
	 <result property="password" column="u_password"/>
	 <result property="gender" column="u_gender"/>
	 <result property="cid" column="u_cid"/>
</resultMap>

然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:

<select id="selectUserById" parameterType="Integer" resultMap="userResultMap">
	select * from t_user
	where u_id = #{id}
</select>

在这里插入图片描述
MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序,那就太好了,但可惜也没有。 而 ResultMap 就是 MyBatis 对这个问题的答案。

结果映射

在这里插入图片描述
在这里插入图片描述

id & result

<id property="id" column="u_id"/>
<result property="username" column="u_username"/>

这些元素是结果映射的基础。id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。

这两者之间的唯一不同是,id 元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。

两个元素都有一些属性:

Id 和 Result 的属性

属性 描述

  • property 映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。否则 MyBatis 将会寻找给定名称的字段(field)。 无论是哪一种情形,你都可以使用常见的点式分隔形式进行复杂属性导航。 比如,你可以这样映射一些简单的东西:“username”,或者映射到一些复杂的东西上:“address.street.number”。
  • column 数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。
  • javaType 一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。
  • jdbcType JDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可以为空值的列指定这个类型。
  • typeHandler 我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的全限定名,或者是类型别名。

支持的 JDBC 类型

为了以后可能的使用场景,MyBatis 通过内置的 jdbcType 枚举类型支持下面的 JDBC 类型。
在这里插入图片描述

一对一

一个用户只属于一个国家
新建一个用户包装类

UserVo.java

package pers.goodwin.mybatis.bean;
public class UserVo extends User {
	private Country country;
	public Country getCountry() {
		return country;
	}
	public void setCountry(Country country) {
		this.country = country;
	}

	@Override
	public String toString() {
		return "UserVo [getId()=" + getId() + ", getUsername()=" + getUsername() + ", getPassword()=" + getPassword()
				+ ", getGender()=" + getGender() +  ", country=" + country + "]";
	}
}

UserMapper.java

public List<UserVo> selectUserVo();

mapper配置

<resultMap id="userVoMap" type="UserVo">
 	<id property="id" column="u_id" />
	 <result property="username" column="u_username"/>
	 <result property="password" column="u_password"/>
	 <result property="gender" column="u_gender"/>
	 <!-- 一对一 -->
	 <association property="country" javaType="country">
		<id property="c_id" column="c_id" />
		<result property="c_countryname" column="c_countryname"/>
	 </association>
</resultMap>
	
<select id="selectUserVo" resultMap="userVoMap">
	select u_id,u_username,u_password,u_gender,c_id,c_countryname
	from t_user
	left join t_country
	on u_cid = c_id
</select>

测试

@Test
	public void Test8() throws IOException {
		InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
		SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();
		SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		
		List<UserVo> userlist = mapper.selectUserVo();
		for (UserVo u : userlist) {
			System.out.println(u);
		}
	}

在这里插入图片描述

一对多

一个国家可以有多个用户
新建一个国家包装类

CountryVo.java

package pers.goodwin.mybatis.bean;

import java.util.List;

public class CountryVo extends Country {
	private List<User> userList;

	public List<User> getUserList() {
		return userList;
	}
	public void setUserList(List<User> userList) {
		this.userList = userList;
	}

	@Override
	public String toString() {
		return "CountryVo [getC_id()=" + getC_id() + ", getC_countryname()=" + getC_countryname() + ", userList="
				+ userList + "]";
	}
}

CountryMapper.java

package pers.goodwin.mybatis.mapper;
import java.util.List;
import pers.goodwin.mybatis.bean.CountryVo;
public interface CountryMapper {
	public List<CountryVo> selectCountryVo();
}

CountryMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pers.goodwin.mybatis.mapper.CountryMapper">

	<resultMap type="CountryVo" id="countryVo">
		<id property="c_id" column="c_id"/>
		<result property="c_countryname" column="c_countryname"/>
		<!-- 一对多关系 -->
		<collection property="userList" ofType="User">
			<id property="id" column="u_id"/>
			<result property="username" column="u_username"/>
			<result property="gender" column="u_gender"/>
		</collection>
	</resultMap>
	<select id="selectCountryVo" resultMap="countryVo">
		select c_id,c_countryname,u_id,u_username,u_gender
		from t_country
		left join t_user
		on c_id = u_cid
	</select>
</mapper>

测试

@Test
	public void Test9() throws IOException {
		InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
		SqlSessionFactoryBuilder ssb = new SqlSessionFactoryBuilder();
		SqlSessionFactory sqlSessionFactory = ssb.build(inputStream);
		SqlSession sqlSession = sqlSessionFactory.openSession();
		CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
		List<CountryVo> list = mapper.selectCountryVo();
		for (CountryVo c : list) {
			System.out.println(c);
		}
	}
==>  Preparing: select c_id,c_countryname,u_id,u_username,u_gender from t_country left join t_user on c_id = u_cid
==> Parameters: 
<==      Total: 6
CountryVo [getC_id()=1, getC_countryname()=中国, userList=[User [id=1, username=隔壁老王, password=null, gender=0, cid=null], User [id=4, username=李四, password=null, gender=1, cid=null]]]
CountryVo [getC_id()=2, getC_countryname()=法国, userList=[User [id=3, username=张三, password=null, gender=0, cid=null]]]
CountryVo [getC_id()=3, getC_countryname()=美国, userList=[User [id=2, username=王五, password=null, gender=1, cid=null]]]
CountryVo [getC_id()=4, getC_countryname()=英国, userList=[User [id=5, username=王八, password=null, gender=0, cid=null]]]
CountryVo [getC_id()=5, getC_countryname()=俄罗斯, userList=[User [id=6, username=李白, password=null, gender=0, cid=null]]]

其他文件

User.java

package pers.goodwin.mybatis.bean;

/**
 * @author goodwin
 *
 */
public class User {
	private Integer  id;
	private String  username;
	private String  password;
	private Integer  gender;
	private Integer  cid;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Integer getGender() {
		return gender;
	}
	public void setGender(Integer gender) {
		this.gender = gender;
	}
	public Integer getCid() {
		return cid;
	}
	public void setCid(Integer cid) {
		this.cid = cid;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + ", gender=" + gender + ", cid="
				+ cid + "]";
	}
	
	
}

Country.java

package pers.goodwin.mybatis.bean;

/**
 * @author goodwin
 *
 */
public class Country {
	private Integer c_id;
	private String c_countryname;
	public Integer getC_id() {
		return c_id;
	}
	public void setC_id(Integer c_id) {
		this.c_id = c_id;
	}
	public String getC_countryname() {
		return c_countryname;
	}
	public void setC_countryname(String c_countryname) {
		this.c_countryname = c_countryname;
	}
	@Override
	public String toString() {
		return "Country [c_id=" + c_id + ", c_countryname=" + c_countryname + "]";
	}
}

db.properties

#database configuration information
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_ssm_mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=111111

log4j.properties

#Global configuration
log4j.rootLogger=DEBUG,stdout
#Console configuration
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.layout.ConversionPattern=%5p [%t] - %m%n

sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- 读取数据库配置文件 -->
	<properties resource="db.properties" />

	<typeAliases>
		<!-- <typeAlias alias="user" type="pers.goodwin.mybatis.bean.User"/> -->

		<!-- 推荐使用扫描包的形式来配置别名 包的形式会扫描包及子包下的所有文件, 以对象类名为别名,大小写不敏感,推荐使用小写 -->
		<package name="pers.goodwin.mybatis.bean" />
	</typeAliases>

	<!-- 配置环境-默认环境id为MySQL -->
	<environments default="MySQL">
		<environment id="MySQL">
			<!-- 使用JDBC事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<!-- 将sql映射文件注册到全局配置文件中 -->
	<mappers>
		<!-- 使用相对于类路径的资源引用 -->
		<!-- <mapper resource="pers/goodwin/mybatis/mapper/UserMapper.xml" /> -->
		<!-- 使用完全限定资源定位符(URL) -->
		<!-- <mapper url="file:///G:\Java\ssm_mybatis_part1\src\pers\goodwin\mybatis\mapper\UserMapper.xml"/> -->
		<!-- 使用映射器接口实现类的完全限定类名 -->
		<!-- <mapper class="pers.goodwin.mybatis.mapper.UserMapper"/> -->
		<!-- 将包内的映射器接口实现全部注册为映射器 -->
		<package name="pers.goodwin.mybatis.mapper" />
	</mappers>
</configuration>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值