MyBatis——使用 resultMap 配置一对一、一对多关系详解

MyBatis——使用resultMap 映射一对一、一对多问题详解


1. MyBaits简介

MyBatis 是一个优秀的持久层框架,它对 jdbc 的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需 要花费精力去处理例如注册驱动、创建 connection、创建 statement、手动设 置参数、结果集检索等 jdbc 繁杂的过程代码。MyBatis 通过 xml 或注解的方 式将要执行的各种 statement(statement、preparedStatemnt、 CallableStatement)配置起来,并通过 java 对象和 statement 中的 sql 进行 映射生成最终执行的 sql 语句,最后由 MyBatis 框架执行 sql 并将结果映射成 java 对象并返回。

与其他的对象关系映射框架不同,MyBatis 并没有将 Java 对象与数据库表关 联起来,而是将 Java 方法与 SQL 语句关联。MyBatis 允许用户充分利用数据 库的各种功能,例如存储过程、视图、各种复杂的查询以及某数据库的专有特 性。如果要对遗留数据库、不规范的数据库进行操作,或者要完全控制 SQL 的执行,MyBatis 是一个不错的选择。

2. 创建Mapper.xml文件需要注意的问题总结
  1. 创建Mapper.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="path"> </mapper>

path填入Mapper文件的路径

创建一个新的 mapper ,需要首先给它取一个 namespace,这相当于是一个 分隔符,因为我们在项目中,会存在很多个 Mapper,每一个 Mapper 中都会 定义相应的增删改查方法,为了避免方法冲突,也为了便于管理,每一个 Mapper 都有自己的 namespace,而且这个 namespace 不可以重复。

  1. xxxMapper.xml和xxxMapper.java 的位置问题

注意,在 Maven 中,默认情况下,Maven 要求我们将 XML 配置、properties 配置等,都放在 resources 目录下,如果我们强行放在 java 目录下,默认情 况下,打包的时候这个配置文件会被自动忽略掉。对于这两个问题,我们有两种解决办法:

  • 不要忽略 XML 配置:
    我们可以在 pom.xml 中,添加如下配置,让 Maven 不要忽略我在 java 目录
    下的 XML 配置:
<build>
	<resources>
	 <resource>
			<directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
    </resource>
        <resource>
            <directory>src/main/resources</directory>
		</resource>
	</resources>
</build>
  • 按照 Maven 的要求来
    按照 Maven 的要求来,将 xml 文件放到 resources 目录下,但是,MyBatis 中默认情况下要求,xxxMapper.xml 和 xxxMapper 接口,必须放在一起, 所以,我们需要手动在 resources 目录下,创建一个和 xxxMapper 接口相同 的目录,这样,我们就不需要在 pom.xml 文件中添加配置了,因为这种写法同时满足 了 Maven 和 MyBatis 的要求。

  • **注意:在resources中创建相同目录时候,不能一次创建多级,只能一级一级的创建,虽然看上去是相同的,但是实际上是不一样的,如果一次性创建多级,编译之后的文件中xxxMapper.xml 和 xxxMapper 接口不会放在一起…(之前吃过大亏,每一次都手动拖拽编译文件…)

  1. application.properties 文件配置
//引入阿里巴巴的数据库连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
//设置驱动、端口号、数据库名、时区
spring.datasource.url=jdbc:mysql://localhost:3306/dataBaseName?serverTimezone=UTC

spring.datasource.username = root
spring.datasource.password = rootroot

server.port=8080
//日志级别 从小到大分别为 trace -> debug -> info -> warn -> error
logging.level.cn.stians.vblog.mapper=debug
3. MyBatis——resultMap 映射写法
  1. 一对一关系: 比如一本书,对应一个作者,对应的pojo如下:
public class Book {
 private Integer id; 
 private String name; 
 private Author author;//Book中装了一个作者
 	...
 	//省略get,set方法
 	...
 }
  • 根据id查询book
	Book getBookById(int id);
<?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="org.javaboy.mybatis.mapper.BookMapper">
<resultMap id="BookWithAuthor" type="org.javaboy.mybatis.model.Book">
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<!-- association 节点用来描述一对一关系-->
<association property="author" javaType="org.javaboy.mybatis.model.Author">
	<id column="aid" property="id"/>
	<result column="aname" property="name"/>
	<result column="aage" property="age"/> 
</association>
</resultMap>
 <select id="getBookById" resultMap="BookWithAuthor">
	SELECT b.*,a.`age` AS aage,a.`id` AS aid,a.`name` AS aname FRO
	M book b,author a WHERE b.`aid`=a.`id` AND b.`id`=#{id} 
</select>
</mapper>
  • 将公共的属性抽出来,可以减少重复的代码
<?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="org.javaboy.mybatis.mapper.BookMapper">
	<resultMap id="BaseResultMap" type="org.javaboy.mybatis.model.Book">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
</resultMap>

<!-- extends 节点用来继承上面的BaseResultMap这个公共的模板,这样就可以不需要写公共的属性了-->
<resultMap id="BookWithAuthor" type="org.javaboy.mybatis.model.Bo ok" extends="BaseResultMap">
<association property="author" javaType="org.javaboy.mybatis.model.Author">
	<id column="aid" property="id"/>
	<result column="aname" property="name"/>
	<result column="aage" property="age"/> </association>
</resultMap>
<select id="getBookById" resultMap="BookWithAuthor">
	SELECT b.*,a.`age` AS aage,a.`id` AS aid,a.`name` AS aname FRO
	M book b,author a WHERE b.`aid`=a.`id` AND b.`id`=#{id}
</select>
</mapper>
  • 使用懒加载

上面这种加载方式,是一次性的读取到所有数据。然后在 resultMap 中做映 射。如果一对一的属性使用不是很频繁,可能偶尔用一下,这种情况下,我们 也可以启用懒加载。懒加载,就是先查询 book,查询 book 的过程中,不去查询 author,当用户 第一次调用了 book 中的 author 属性后,再去查询 author。

  • 再提供一个方法
Book getBookById(Integer id); 
Author getAuthorById(Integer id);
<resultMap id="BaseResultMap" type="org.javaboy.mybatis.model.Book"> 
	<id column="id" property="id"/>
	<result column="name" property="name"/>
</resultMap>
<resultMap id="BookWithAuthor2" type="org.javaboy.mybatis.model.Book" extends="BaseResultMap">
	<association property="author" javaType="org.javaboy.mybatis.model.Author" select="org.javaboy.mybatis.mapper.BookMapper.getAuthorById" column="aid" fetchType="lazy"/>
</resultMap>
<select id="getBookById2" resultMap="BookWithAuthor2">
	 select * from book where id = #{id}; 
</select>
<select id="getAuthorById" resultType="org.javaboy.mybatis.model.Author">
	select * from author where id = #{aid}; 
</select>

这里,定义 association 的时候,不直接指定映射的字段,而是指定要执行的 方法,通过 select 字段来指定,column 表示执行方法时传递的参数字段,最 后的 fetchType 表示开启懒加载。
当然,要使用懒加载,还需在全局配置中开启:

<settings>
	<setting name="lazyLoadingEnabled" value="true"/> 
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>
  1. 一对多查询
    比如一个用户对应多个角色,对应的pojo类如下:
public class User {
	private Integer id; 
	private String username; 
	private String password; 
	private List<Role> roles;
	
	//省略get、set方法
	...
	}
  • 提供方法,根据id查询用户
	User getUserById(Integer id);
<resultMap id="UserWithRole" type="org.javaboy.mybatis.model.User"> <id column="id" property="id"/>
	<result column="username" property="username"/>
	<result column="password" property="password"/>
	<collection property="roles" ofType="org.javaboy.mybatis.model.Role">
		<id property="id" column="rid"/>
		<result property="name" column="rname"/> 
		<result property="nameZh" column="rnameZH"/>
	</collection>
</resultMap>
    
 <select id="getUserById" resultMap="UserWithRole">
	SELECT u.*,r.`id` AS rid,r.`name` AS rname,r.`nameZh` AS rnameZh
	FROM USER u,role r,user_role ur WHERE u.`id`=ur.`uid` AND ur.`rid`=r.`id` AND u.`id`=#{id}
</select>

在 resultMap 中,通过 collection 节点来描述集合的映射关系。在映射时,会自动将一的一方数据集合并,然后将多的一方放到集合中,能实现这一点,靠的就是 id 属性。

  • 这个一对多,也可以做成懒加载的形式,那我们首先提供一个角色查询 的方法:
	User getUserById(Integer id);	
	List<Role> getRolesByUid(Integer id);

然后,在 XML 文件中,处理懒加载

<resultMap id="UserWithRole" type="org.javaboy.mybatis.model.User"> <id column="id" property="id"/>
	<result column="username" property="username"/>
	<result column="password" property="password"/>
	<collection property="roles" select="org.javaboy.mybatis.mapper.UserMapper.getRolesByUid" column="id" fetchType="lazy">
	</collection>
</resultMap>

<select id="getUserById" resultMap="UserWithRole"> 
	select * from user where id=#{id};
</select>

<!--这里也可以写到Role类对象的mapper.xml中去-->
<select id="getRolesByUid" resultType="org.javaboy.mybatis.model.Role">
	SELECT r.* FROM role r,user_role ur WHERE r.`id`=ur.`rid` AND ur.`uid`=#{id}
</select>
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Mybatis中的ResultMap可以用来映射一对多关系。在ResultMap中,可以使用collection标签来定义一个集合属性,用来表示一对多关系。在集合属性中,可以使用result标签来定义子对象的映射规则。例如: <resultMap id="userMap" type="User"> <id property="id" column="id"/> <result property="name" column="name"/> <collection property="orders" ofType="Order"> <id property="id" column="order_id"/> <result property="name" column="order_name"/> </collection> </resultMap> 在上面的例子中,User对象包含一个orders属性,用来表示一个用户可以有多个订单。使用collection标签来定义orders属性,并使用ofType属性来指定子对象的类型为Order。在集合属性中,使用id和result标签来定义子对象的映射规则。这样,在查询结果中,就可以将多个订单映射到一个User对象中的orders属性中。 ### 回答2: 在MyBatis中,ResultMap是一种用于将查询到的结果集映射成Java对象的机制。当查询结果集中包含多个对象的属性时,就需要使用ResultMap一对多映射。 一对多映射的实现,需要在ResultMap中定义一个collection元素来表示将多个对象映射成一个集合。collection元素中需要设置property、ofType和select等属性。 property属性表示映射到结果集中的查询条件,也就是查询多个对象时需要根据哪个属性进行关联。 ofType属性表示集合元素的类型,这里表示集合中元素的类型为哪个Java类。 select属性表示查询的语句,对应于查询结果集的collection列。 例如,以下是一段使用ResultMap实现一对多映射的示例代码: <resultMap id="UserMap" type="User"> <id column="id" property="id"/> <result column="username" property="username"/> <result column="password" property="password"/> <collection property="books" ofType="Book" select="selectBooksByUser" column="id"/> </resultMap> 在上面的代码中,UserMap是一个ResultMap配置,books是User类中的一个List<Book>类型属性。通过collection元素的配置,表示User对象与多个Book对象之间存在一对多关系。 需要注意的是,以上的示例代码中,还需要在mapper文件中定义selectBooksByUser语句,用于查询对应的Book对象。同时,需要配置查询语句中的查询条件,也就是column属性,与User对象的id属性关联起来。 通过以上的配置,如果查询结果集中包含了User对象与多个Book对象,MyBatis就会根据配置进行自动映射,将查询结果集中的数据转化为Java对象的形式,方便我们进行业务逻辑的处理。 ### 回答3: MyBatis是一种轻量级的ORM框架,支持复杂的SQL查询。其中,ResultMapMyBatis非常重要的一种映射规则,可以将查询结果映射到Java对象中。 在MyBatis中,使用ResultMap进行一对多的映射时,可以通过以下步骤完成: 1. 定义主实体类和从实体类 在一对多映射中,主实体类代表一端,从实体类代表多端。例如,在一个学校的管理系统中,Student代表主实体类,Grade代表从实体类。一名学生可以拥有多个成绩单。 2. 在主实体类中增加从实体类的集合 在主实体类中增加从实体类的集合属性,如下所示: public class Student { private int id; private String name; private List<Grade> grades; } 3. 定义ResultMap 定义ResultMap时,需要使用collection标签来映射从实体类的集合属性。注意,collection标签的属性property应该指向主实体类中的集合属性,同时需要指定从实体类的ResultMap,如下所示: <resultMap id="studentResultMap" type="Student"> <id property="id" column="id"/> <result property="name" column="name"/> <collection property="grades" ofType="Grade" resultMap="gradeResultMap"/> </resultMap> 4. 定义从实体类的ResultMap 在从实体类的ResultMap中,需要定义每一列的映射关系。同样地,需要定义id标签,指向主实体类的外键列,如下所示: <resultMap id="gradeResultMap" type="Grade"> <id property="id" column="id"/> <result property="subject" column="subject"/> <result property="score" column="score"/> <association property="student" javaType="Student"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> </association> </resultMap> 5. 编写查询语句 最后,编写查询语句时,需要使用select标签,并在其中指定ResultMap,如下所示: <select id="getStudent" resultMap="studentResultMap"> SELECT s.id, s.name, g.id, g.subject, g.score, g.student_id, s2.name as student_name FROM student s LEFT JOIN grade g on s.id = g.student_id LEFT JOIN student s2 on g.student_id = s2.id </select> 这样,就完成了从数据库中查询学生及其所拥有的成绩单,并将结果映射为Student的对象。其中,每个Student对象的grades属性是一个List,其中包含多个Grade的对象。 以上就是使用ResultMap实现MyBatis一对多映射的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值