MyBatis 教程

对象一对多映射

前面章节介绍了一对一映射,本章节将介绍怎样实现一对多映射。

在 MyBatis 中,使用 <resultMap> 配合 <collection> 标签实现一对多映射。<collection> 标签 DTD 定义如下:

<!ELEMENT collection (constructor?,id*,result*,association*,collection*, discriminator?)>
<!ATTLIST collection
property CDATA #REQUIRED
column CDATA #IMPLIED
javaType CDATA #IMPLIED
ofType CDATA #IMPLIED
jdbcType CDATA #IMPLIED
select CDATA #IMPLIED
resultMap CDATA #IMPLIED
typeHandler CDATA #IMPLIED
notNullColumn CDATA #IMPLIED
columnPrefix CDATA #IMPLIED
resultSet CDATA #IMPLIED
foreignColumn CDATA #IMPLIED
autoMapping (true|false) #IMPLIED
>

根据上面 DTD 得知,<collection> 标签下允许使用 <constructor>、<id>、<result>、<association>、<collection> 和 <discriminator> 标签。该标签也定义了很多属性,每个属性含义如下:

  • property:映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。否则 MyBatis 将会寻找给定名称的字段(field)。 无论是哪一种情形,你都可以使用常见的点式分隔形式进行复杂属性导航。 比如,你可以这样映射一些简单的东西:“username”,或者映射到一些复杂的东西上:“address.street.number”。

  • column:数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。

  • javaType:一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。

  • ofType:完整java类名或别名(集合所包括的类型)

  • jdbcType:JDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可以为空值的列指定这个类型。

  • select:用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句。具体请参考关联元素。

  • resultMap:结果映射的 ID,可以将此关联的嵌套结果集映射到一个合适的对象树中。 它可以作为使用额外 select 语句的替代方案。它可以将多表连接操作的结果映射成一个单一的 ResultSet。这样的 ResultSet 有部分数据是重复的。 为了将结果集正确地映射到嵌套的对象树中, MyBatis 允许你“串联”结果映射,以便解决嵌套结果集的问题。使用嵌套结果映射的一个例子在表格以后。

  • typeHandler:指定自定义类型处理器

  • notNullColumn:默认情况下,在至少一个被映射到属性的列不为空时,子对象才会被创建。 你可以在这个属性上指定非空的列来改变默认行为,指定后,Mybatis 将只在这些列非空时才创建一个子对象。可以使用逗号分隔来指定多个列。默认值:未设置(unset)。

  • columnPrefix:当连接多个表时,你可能会不得不使用列别名来避免在 ResultSet 中产生重复的列名。指定 columnPrefix 列名前缀允许你将带有这些前缀的列映射到一个外部的结果映射中。 详细说明请参考后面的例子。

  • resultSet:这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。

  • foreignColumn:指定外键对应的列名,指定的列将与父类型中 column 的给出的列进行匹配。

  • autoMapping:如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。

示例代码如下:

<resultMap id="ormUser" type="com.hxstrive.mybatis.orm.demo1.ORMUser">
   <id column="user_id" jdbcType="INTEGER" property="userId" />
   <result column="name" jdbcType="VARCHAR" property="name" />
   <result column="sex" jdbcType="VARCHAR" property="sex" />
   <result column="age" jdbcType="INTEGER" property="age" />
   <result column="salary" jdbcType="DOUBLE" property="salary" />
   <result column="borthday" jdbcType="DATE" property="borthday" />
   <!-- 映射关联的List -->
   <collection column="user_id" property="contactList"
      ofType="com.hxstrive.mybatis.orm.demo1.ORMContact">
      <id column="id" jdbcType="INTEGER" property="id" />
      <result column="user_id" jdbcType="INTEGER" property="userId" />
      <result column="usage" jdbcType="VARCHAR" property="usage" />
      <result column="number" jdbcType="VARCHAR" property="number" />
   </collection>
</resultMap>

上面示例中,<collection> 标签将根据“user_id”列到 user_concat 表中查找指定用户的所有联系方式,然后将查询结果映射到 contactList 属性。

示例代码

(1)MyBatis 配置文件 mybatis-cfg.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="database.properties"/>
    <environments default="MySqlDatabase" >
        <environment id="MySqlDatabase" >
            <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>
    <mappers>
        <mapper resource="com/hxstrive/mybatis/orm/demo1/ORMMapper.xml"/>
    </mappers>
</configuration>

(2)定义 JavaBean 实体

a、ORMUser.java

package com.hxstrive.mybatis.orm.demo1;

import java.util.Date;
import java.util.List;

public class ORMUser {
   private Integer userId;
   private String name;
   private String sex;
   private Integer age;
   private Double salary;
   private Date borthday;
   private byte[] face;
   private List<ORMContact> contactList;

   // 忽略 getter 和 setter

   @Override
   public String toString() {
      return "ORMUser{" +
            "userId=" + userId +
            ", name='" + name + '\'' +
            ", sex='" + sex + '\'' +
            ", age=" + age +
            ", salary=" + salary +
            ", borthday=" + borthday +
            ", contactList=" + contactList +
            '}';
   }
}

b、ORMContact.java

package com.hxstrive.mybatis.orm.demo1;

public class ORMContact {
   private Integer id;
   private Integer userId;
   private String usage;
   private String number;
   private ORMUser user;

   // 忽略 getter 和 setter

   @Override
   public String toString() {
      return "ORMContact{" +
            "id=" + id +
            ", userId=" + userId +
            ", usage='" + usage + '\'' +
            ", number='" + number + '\'' +
            ", user=" + user +
            '}';
   }
}

(3)定义 Mapper 接口和配置文件

a、ORMMapper.java

package com.hxstrive.mybatis.orm.demo1;

import java.util.List;

public interface ORMMapper {
   List<ORMUser> joinSelect01();
}

b、ORMMapper.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="com.hxstrive.mybatis.orm.demo1.ORMMapper">

   <!-- 一对多映射 -->
   <resultMap id="ormUser" type="com.hxstrive.mybatis.orm.demo1.ORMUser">
      <id column="user_id" jdbcType="INTEGER" property="userId" />
      <result column="name" jdbcType="VARCHAR" property="name" />
      <result column="sex" jdbcType="VARCHAR" property="sex" />
      <result column="age" jdbcType="INTEGER" property="age" />
      <result column="salary" jdbcType="DOUBLE" property="salary" />
      <result column="borthday" jdbcType="DATE" property="borthday" />
      <!-- 映射关联的List -->
      <collection column="user_id" property="contactList"
         ofType="com.hxstrive.mybatis.orm.demo1.ORMContact">
         <id column="id" jdbcType="INTEGER" property="id" />
         <result column="user_id" jdbcType="INTEGER" property="userId" />
         <result column="usage" jdbcType="VARCHAR" property="usage" />
         <result column="number" jdbcType="VARCHAR" property="number" />
      </collection>
   </resultMap>
   <select id="joinSelect01" resultMap="ormUser">
      select a.`user_id`, a.`name`, a.`sex`, a.`age`, a.`salary`, a.`borthday`,
         b.`id`, b.`user_id`, b.`usage`, b.`number`
      from `user` a
      join `user_contact` b on a.`user_id`=b.`user_id`
   </select>

</mapper>

(4)客户端代码如下:

package com.hxstrive.mybatis.orm.demo1;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;

public class ORMDemo {

    public static void main(String[] args) throws Exception {
        String cfgName = "com/hxstrive/mybatis/orm/demo1/mybatis-cfg.xml";
        InputStream input = Resources.getResourceAsStream(cfgName);
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlFactory = factoryBuilder.build(input);
        SqlSession sqlSession = sqlFactory.openSession(true);
        ORMMapper ormMapper = sqlSession.getMapper(ORMMapper.class);

        List<ORMUser> userList = ormMapper.joinSelect01();
        for ( ORMUser user : userList ) {
            System.out.println(user);
        }
    }

}

运行客户端代码,输出结果如下:

2020-09-15 21:59:09,215 DEBUG [org.apache.ibatis.logging.LogFactory] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
2020-09-15 21:59:09,244 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
2020-09-15 21:59:09,244 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
2020-09-15 21:59:09,244 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
2020-09-15 21:59:09,244 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
2020-09-15 21:59:09,401 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Opening JDBC Connection
2020-09-15 21:59:09,877 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Created connection 250370634.
2020-09-15 21:59:09,879 DEBUG [com.hxstrive.mybatis.orm.demo1.ORMMapper.joinSelect01] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@eec5a4a]
2020-09-15 21:59:09,880 DEBUG [com.hxstrive.mybatis.orm.demo1.ORMMapper.joinSelect01] - ==>  Preparing: select a.`user_id`, a.`name`, a.`sex`, a.`age`, a.`salary`, a.`borthday`, b.`id`, b.`user_id`, b.`usage`, b.`number` from `user` a join `user_contact` b on a.`user_id`=b.`user_id` 
2020-09-15 21:59:10,048 DEBUG [com.hxstrive.mybatis.orm.demo1.ORMMapper.joinSelect01] - ==> Parameters: 
2020-09-15 21:59:10,143 DEBUG [com.hxstrive.mybatis.orm.demo1.ORMMapper.joinSelect01] - <==      Total: 5
ORMUser{userId=1, name='赫仑', sex='男', age=27, salary=7800.0, borthday=Wed Jun 04 00:00:00 CST 1902, contactList=[ORMContact{id=1, userId=1, usage='手机号码', number='15787782291', user=null}]}
ORMUser{userId=2, name='张小凡', sex='男', age=30, salary=8670.0, borthday=Wed Aug 22 00:00:00 CDT 1990, contactList=[ORMContact{id=2, userId=2, usage='家庭号码', number='028-82234543', user=null}]}
ORMUser{userId=3, name='叶星云', sex='女', age=31, salary=6890.0, borthday=Mon Feb 27 00:00:00 CST 1989, contactList=[ORMContact{id=3, userId=3, usage='工作号码', number='028-78675599', user=null}, ORMContact{id=4, userId=3, usage='生活号码', number='15198892234', user=null}, ORMContact{id=5, userId=3, usage='私密电话', number='15882334337', user=null}]}
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号