package com.emerson.learning.pojo;
import java.sql.Timestamp;
public class Customer {
/**
*
*/
private int customerId;
/**
*
*/
private String customerName;
/**
*
*/
private int isValid;
/**
*
*/
private Timestamp createdTime;
/**
*
*/
private Timestamp updateTime;
/**
*
*/
private User userInfo;
@Override
public String toString() {
return "Customer [customerId=" + customerId + ", customerName=" + customerName + ", isValid=" + isValid
+ ", createdTime=" + createdTime + ", updateTime=" + updateTime + ", userInfo=" + userInfo + "]";
}
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public int getIsValid() {
return isValid;
}
public void setIsValid(int isValid) {
this.isValid = isValid;
}
public Timestamp getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Timestamp createdTime) {
this.createdTime = createdTime;
}
public Timestamp getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Timestamp updateTime) {
this.updateTime = updateTime;
}
public User getUserInfo() {
return userInfo;
}
public void setUserInfo(User userInfo) {
this.userInfo = userInfo;
}
}
第二步,修改映射文件。我们先使用嵌套查询方式来实现为销售加载客户列表。首先在resultMap中增加客户集合映射的定义。
嵌套查询
<!-- 定义一对多集合信息(每个销售人员对应多个客户) -->
<collection property="customers" javaType="ArrayList" column="sales_id" ofType="Customer" select="getCustomerForSales" />
集合映射的定义与关联映射定义很相似,除了关键字不同外,还多了两个属性JavaType和ofType。
property用于指定在Java实体类是保存集合关系的属性名称
JavaType用于指定在Java实体类中使用什么类型来保存集合数据,多数情况下这个属性可以省略的。
column用于指定数据表中的外键字段名称。
ofType用于指定集合中包含的类型。
select用于指定查询语句。
然后再定义查询客户的查询语句。
<select id="getCustomerForSales" resultType="com.emerson.learning.pojo.Customer">
SELECT c.customer_id, c.customer_name, c.user_id, c.is_valid,
c.created_time, c.update_time
FROM customer c INNER JOIN customer_sales s USING(customer_id)
WHERE s.sales_id = #{id}
</select>
需要注意的是,无论是关联还是集合,在嵌套查询的时候,查询语句的定义都不需要使用parameterType属性定义传入的参数类型,因为通常作为外键的,都是简单数据类型,查询语句会自动使用定义在association或是collection元素上column属性作为传入参数的。
运行测试用例,看到如下结果就说明我们的映射文件是正确的了。
Opening JDBC Connection
Created connection 632249781.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@25af5db5]
==> Preparing: SELECT sales_id, sales_name, sales_phone, sales_fax, sales_email, salesman.is_valid, salesman.created_time, salesman.update_time, sys_user.user_id as user_id, user_name, user_password, nick_name, email as user_email, sys_user.is_valid as user_is_valid, sys_user.created_time as user_created_time, sys_user.update_time as user_update_time FROM salesman left outer join sys_user using(user_id) WHERE sales_id=?
==> Parameters: 2(Integer)
<== Columns: sales_id, sales_name, sales_phone, sales_fax, sales_email, is_valid, created_time, update_time, user_id, user_name, user_password, nick_name, user_email, user_is_valid, user_created_time, user_update_time
<== Row: 2, Bing Gu, 021-3418 1999, null, Bing.Gu@emerson.com, 1, 2015-10-01 20:21:26.0, 2015-10-01 21:56:40.0, 25, binggu, 5f4dcc3b5aa765d61d8327deb882cf99, Bing Gu, null, 1, 2015-09-30 22:04:34.0, 2015-09-30 22:04:34.0
====> Preparing: SELECT c.customer_id, c.customer_name, c.user_id, c.is_valid, c.created_time, c.update_time FROM customer c INNER JOIN customer_sales s USING(customer_id) WHERE s.sales_id = ?
====> Parameters: 2(Integer)
<==== Columns: customer_id, customer_name, user_id, is_valid, created_time, update_time
<==== Row: 161, 客户1, null, 1, 2015-10-01 20:24:05.0, 2015-10-01 20:24:05.0
<==== Row: 163, 客户2, null, 1, 2015-10-01 20:24:05.0, 2015-10-01 20:24:05.0
<==== Row: 164, 客户3, null, 1, 2015-10-01 20:24:05.0, 2015-10-01 20:24:05.0
<==== Total: 3
<== Total: 1
我们看到这里与数据库进行了两查询交互,说明这里仍然存在着“N+1”的问题。下面,我们改用嵌套结果的方式来实现销售与客户的映射关系。
嵌套结果
<resultMap id="salesResultMap" type="com.emerson.learning.pojo.Sales">
<id property="salesId" column="sales_id" />
<result property="salesName" column="sales_name" />
<result property="phone" column="sales_phone" />
<result property="fax" column="sales_fax" />
<result property="email" column="sales_email" />
<result property="isValid" column="is_valid" />
<result property="createdTime" column="created_time" />
<result property="updateTime" column="update_time" />
<!-- 定义多对一关联信息(嵌套结果方式) -->
<association property="userInfo" resultMap="userResult" />
<!-- 定义一对多集合信息(每个销售人员对应多个客户) -->
<!-- <collection property="customers" column="sales_id" select="getCustomerForSales" /> -->
<collection property="customers" ofType="com.emerson.learning.pojo.Customer">
<id property="customerId" column="customer_id" />
<result property="customerName" column="customer_name" />
<result property="isValid" column="is_valid" />
<result property="createdTime" column="created_time" />
<result property="updateTime" column="update_time" />
<!-- 映射客户与登录用户的关联关系,请注意columnPrefix属性 -->
<association property="userInfo" resultMap="userResult" columnPrefix="cu_" />
</collection>
</resultMap>
这里将客户的映射关系直接写在了销售的resultMap中。上述代码与关联映射十分相似,只是有一点需要朋友们留心,那就是在对客户数据进行映射的时候,我们使用了association元素的一个新的属性columnPrefix。这个属性是做什么用的呢?从名字上理解,就是给每个栏位之前加上前缀。Bingo!答对了,那么什么情况下会使用到这个属性呢?后面我们会结合着修改后的查询语句来说明这个属性的使用场景。请耐心的往下看。:)
映射结果修改好了,紧接着我们就要修改查询语句了。
<select id="getById" parameterType="int" resultMap="salesResultMap">
SELECT
s.sales_id, s.sales_name, s.sales_phone, s.sales_fax, s.sales_email,
s.is_valid, s.created_time, s.update_time,
su.user_id as user_id, su.user_name, su.user_password, su.nick_name,
su.email as user_email,
su.is_valid as user_is_valid,
su.created_time as user_created_time,
su.update_time as user_update_time,
c.customer_id, c.customer_name, c.is_valid as customer_is_valid,
c.created_time as customer_created_time,
c.update_time as customer_update_time,
cu.user_id as cu_user_id, cu.user_name as cu_user_name, cu.user_password as cu_user_password,
cu.nick_name as cu_nick_name, cu.email as cu_user_email, cu.is_valid as cu_user_is_valid,
cu.created_time as cu_user_created_time, cu.update_time as cu_user_update_time
FROM
salesman s LEFT OUTER JOIN sys_user su ON s.user_id = su.user_id
INNER JOIN customer_sales cs USING(sales_id)
LEFT OUTER JOIN customer c USING(customer_id)
LEFT OUTER JOIN sys_user cu ON c.user_id = cu.user_id
WHERE sales_id=#{id}
</select>
这个语句乍看起来有些复杂,其实很容易理解。这里用到了四张数据表,销售、客户、客房销售关系表和登录用户表。具体的字段我就不说了,主要说一下这个登录用户表。这张数据表在查询语句中出现了两次,为什么呢?因为销售与登录用户有关联关系,同样地,客户也与登录用户表有关联关系,所以我们需要对用户表进行两次Join操作。
那么问题来了,销售要用户有关联,客户也要与用户有关联,这种映射语句应该如何写呢?难道要对用户表写两次映射?聪明的朋友一定会说,我们可以复用之前写过的用户映射结果集呀!答案是肯定的。我们不妨在这里再次贴出这段代码,一起回忆一下。
<resultMap id="userResult" type="User">
<id property="userId" column="user_id" />
<result property="userName" column="user_name" />
<result property="userPassword" column="user_password" />
<result property="nickName" column="nick_name" />
<result property="email" column="user_email" />
<result property="isValid" column="user_is_valid" />
<result property="createdTime" column="user_created_time" />
<result property="updateTime" column="user_update_time" />
</resultMap>
数据表中的字段与Java实体类中的属性的映射关系是一一对应的,Mybatis会根据我们定义的映射关系,将数据表中字段的映射到Java实体类属性上。
可是我们的查询语句中对用户表进行了两次Join操作,第一次是销售与用户的Join,第二次是客户与用户的Join。而SQL语句是不允许在同一条查询语句中出现相同字段名的(虽然我们有时候会这样写,但是数据库会自动帮我们为重名的字段名起个别名的,比如在字段名后添加数字)。如果我们为第二次Join进来的用户表中的字段使用别名方式,那么就会导致映射的到客户类中的用户信息缺失,因为字段名与我们在映射文件中的定义不一致。如何解决这个问题呢?这时候该columnPrefix属性出场了。
Mybatis也考虑到这种情况的出现,她允许我们在重复出现的字段名前加上一个统一的字符前缀,这样就可以有效的避免字段重名,又可以复用之前定义的映射结果集。
在上述的查询语句中,我们为第二次Join进来的用户表中的字段都加上了“cu_”做为区分重名字段的前缀,同时使用columnPrefix属性告诉Mybatis在第二次对用户表映射的时候,将字段名是以“cu_”打头的字段值映射到Java实体类属性当中。这样就可以正确的把客户与用户的关联信息映射到Customer对象当中了。
<association property="userInfo" resultMap="userResult" columnPrefix="cu_" />
上述的表达可能有些臃肿,不知道小伙朋友们明白了没有。理工男的写作水平,你们懂的。
彩蛋奉上(共享不同映射文件中的结果集)
我们之前在User.xml文件中定义过用户表的映射结果集,现在在Sales.xml中也需要使用到同样的结果集,是否可以直接跨文件引用呢?答案是肯定的了,不然对于同一个映射结果集,我们要多处编写,多处维护,这样不仅工作量大,对日后的维护也带来了一定的麻烦。我们只需要在引用处使用结果集的全限定名就可以了。
<resultMap id="salesResultMap" type="com.emerson.learning.pojo.Sales">
<id property="salesId" column="sales_id" />
<result property="salesName" column="sales_name" />
<result property="phone" column="sales_phone" />
<result property="fax" column="sales_fax" />
<result property="email" column="sales_email" />
<result property="isValid" column="is_valid" />
<result property="createdTime" column="created_time" />
<result property="updateTime" column="update_time" />
<!-- 定义多对一关联信息(嵌套查询方式) -->
<!-- <association property="userInfo" column="user_id" javaType="User"
select="selectUser" fetchType="lazy"> </association> -->
<!-- 定义多对一关联信息(嵌套结果方式) -->
<association property="userInfo" resultMap="com.emerson.learning.xml.user.userResult" />
<!-- 定义一对多集合信息(每个销售人员对应多个客户) -->
<!-- <collection property="customers" column="sales_id" select="getCustomerForSales"
/> -->
<collection property="customers" ofType="com.emerson.learning.pojo.Customer">
<id property="customerId" column="customer_id" />
<result property="customerName" column="customer_name" />
<result property="isValid" column="is_valid" />
<result property="createdTime" column="created_time" />
<result property="updateTime" column="update_time" />
<association property="userInfo" resultMap="com.emerson.learning.xml.user.userResult" columnPrefix="cu_" />
</collection>
</resultMap>
相关推荐
MyBatis作为一款轻量级的Java持久层框架,提供了灵活的数据映射功能,使得数据库操作变得简单。在处理复杂的关联关系时,MyBatis的一对多映射机制显得尤为重要。一对多映射指的是一个父类实体对应多个子类实体的关系...
在处理复杂映射时,Mybatis提供了解决方案,如集合映射、嵌套结果映射、关联映射等,这些功能使得在ORM(对象关系映射)过程中能更高效地处理数据。 【描述】"Mybatis系列教程Mybatis复杂映射开发共6页.pdf.zip" ...
在MyBatis中,关联映射是处理对象关系映射(ORM)的重要部分,用于描述实体类之间的关联关系,如一对一(OneToOne)、一对多(OneToMany)和多对多(ManyToMany)。下面我们将深入探讨这些关联映射的实现和原理。 ...
在上述示例中,我们可以添加 `collection` 元素来映射 `Post` 和 `Comment` 集合。 通过这种方式,MyBatis 可以自动根据 ResultMap 的配置,将 SQL 查询的结果转换为复杂的对象结构,使得数据操作更加直观和高效。...
Mybatis关联映射是数据库操作中的一个重要概念,它允许我们在SQL查询中处理一对多、多对一、多对多等复杂关系。在这个"Mybatis关联映射Demo"中,我们将深入探讨如何在Mybatis框架中实现这些关系映射,以便更好地理解...
SpringBoot 中 MyBatis 表关联映射关系(一对多嵌套:结果方式) 在 SpringBoot 中,MyBatis 是一个非常流行的持久层框架,它提供了强大的持久化功能,能够将 Java 对象与数据库表进行映射。在实际开发中,我们经常...
在MyBatis框架中,一对多和一对一映射是数据对象关系映射的重要概念,用于处理数据库中的关联关系。在本资源包"Mybatis一对一一多映射.rar"中,我们主要探讨这两个映射方式以及如何在MyBatis配置中实现它们。 首先...
1. **配置映射文件**:在MyBatis的映射文件中,你需要定义两个实体类(例如,Student和Course)的映射,以及它们之间的关联映射。关联映射通常通过`<association>`或`<collection>`标签来实现。 2. **关联查询**:...
Mybatis是一款广泛使用的持久层框架,它为应用程序提供了动态SQL、存储过程以及高级映射等优秀特性。复杂映射开发是Mybatis框架中的一个重要部分,它支持将单个结果集映射到复杂类型的嵌套结构中。 首先,Mybatis的...
关联映射是MyBatis中处理对象与对象间关联关系的关键特性,尤其在企业级应用开发中,面对复杂的数据库表关联,关联映射能有效地简化数据访问逻辑。 在关系型数据库中,常见的关联关系有三种:一对一(One-to-One)...
**MyBatis关联映射详解** 在Java开发中,MyBatis作为一个优秀的持久层框架,提供了灵活的数据映射功能,使得数据库操作变得简单而高效。其中,关联映射是MyBatis中的一个重要特性,用于处理数据库中复杂的关系,如...
MyBatis是一个强大的Java持久层框架,它简化了数据库与Java应用之间的交互,通过XML或注解的方式将SQL语句映射到Java方法上。在本主题中,我们将深入探讨MyBatis中的表实体映射代码,以及如何利用MyBatis Generator...
### Mybatis关联映射 #### 一、关联映射概览 在MyBatis中,关联映射是一种处理复杂查询结果的重要技术。当查询的数据涉及多个表时,使用关联映射能够有效地组织这些数据,使其按照面向对象的方式进行展现。 #### ...
3. **Mybatis配置**:mybatis-config.xml定义全局配置,mapper接口和XML映射文件负责SQL语句。 4. **数据库连接配置**:在资源文件中配置Oracle数据库连接信息,如数据源(DataSource)。 5. **Web部署描述符**:web...
在Java开发中,MyBatis是一个非常流行的持久层框架,它简化了数据库操作与Java对象之间的映射。本文将深入探讨如何使用MyBatis的注解配置来实现一对多关系映射,以此来提高开发效率并减少代码冗余。 首先,我们需要...
在Java代码中,你可以通过MyBatis的SqlSession对象来获取父类对象,并自动加载其关联的子类集合: ```java User user = sqlSession.selectOne("com.example.getUser", userId); List<Order> orders = user....
在IT行业中,Mybatis是一个非常重要的持久层框架,它提供了灵活的SQL映射和对象关系映射功能,使得开发人员可以更加便捷地操作数据库。"Mybatis系列课程-Association"显然是一个专门针对Mybatis中“关联”这一概念的...
**MyBatis** 是一个优秀的持久层框架,它简化了Java与数据库之间的交互,通过XML或注解方式配置和映射原生信息,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。在本项目中,...
在本篇关于MyBatis框架的学习中,我们将深入探讨一对一关联映射和一对多关联映射的概念、配置以及在实际开发中的应用。MyBatis是一个优秀的持久层框架,它允许开发者将SQL语句直接写在XML配置文件或者注解中,从而...
在Java开发中,MyBatis作为一个轻量级的持久层框架,因其强大的映射能力和灵活的SQL构建方式,被广泛应用于各种项目中。本篇主要探讨的是MyBatis中的高级映射之一——一对多查询。在数据库关系模型中,一对多关系是...