`
bit1129
  • 浏览: 1070006 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【持久化框架MyBatis3四】MyBatis3一对一关联查询

 
阅读更多

 

当两个实体具有1对1的对应关系时,可以使用One-To-One的进行映射关联查询

 

One-To-One示例数据

以学生表Student和地址信息表为例,每个学生都有都有1个唯一的地址(现实中,这种对应关系是不合适的,因为人和地址是多对一的关系),这里只是演示目的

 

学生表

 

CREATE TABLE STUDENTS 
(
  STUD_ID INT(11) NOT NULL AUTO_INCREMENT,
  NAME VARCHAR(50) NOT NULL,
  EMAIL VARCHAR(50) NOT NULL,
  PHONE VARCHAR(15) DEFAULT NULL,  
  DOB DATE DEFAULT NULL,
  GENDER VARCHAR(6) DEFAULT NULL, 
  BIO LONGTEXT DEFAULT NULL,
  PIC BLOB DEFAULT NULL,
  ADDR_ID INT(11) DEFAULT NULL, 
  PRIMARY KEY (STUD_ID),
  UNIQUE KEY UK_EMAIL (EMAIL),
  CONSTRAINT FK_STUDENTS_ADDR FOREIGN KEY (ADDR_ID) REFERENCES ADDRESSES (ADDR_ID)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=UTF-8;

 

地址表:

 

CREATE TABLE ADDRESSES 
(
  ADDR_ID INT(11) NOT NULL AUTO_INCREMENT,
  STREET VARCHAR(50) NOT NULL,
  CITY VARCHAR(50) NOT NULL,
  STATE VARCHAR(50) NOT NULL,
  ZIP VARCHAR(10) DEFAULT NULL,
  COUNTRY VARCHAR(50) NOT NULL,
  PRIMARY KEY (ADDR_ID)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=UTF-8;

 

样例数据:

 

 

INSERT INTO ADDRESSES (ADDR_ID,STREET,CITY,STATE,ZIP,COUNTRY) VALUES 
 (1,'4891 Pacific Hwy','San Diego','CA','92110','San Diego'),
 (2,'2400 N Jefferson St','Perry','FL','32347','Taylor'),
 (3,'710 N Cable Rd','Lima','OH','45825','Allen'),
 (4,'5108 W Gore Blvd','Lawton','OK','32365','Comanche');

-- Sample data for table STUDENTS

INSERT INTO STUDENTS (STUD_ID,NAME,EMAIL,PHONE,DOB,BIO,PIC,ADDR_ID) VALUES 
 (1,'Timothy','timothy@gmail.com','123-123-1234','1988-04-25',NULL,NULL,3),
 (2,'Douglas','douglas@gmail.com','789-456-1234','1990-08-15',NULL,NULL,4);

 

从上面的建表的sql中,可以看到,STUDENTS表通过外键ADDR_ID与ADDRESSES表建立1:1的映射关系

 

 

建立Address-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="com.mybatis3.mappers.AddressMapper">
	<!--Address是在MyBatis主配置文件中定义的类型别名-->
        <!--AddressResult这个resultMap对ADDRESSES表进行了SQL和Model的映射-->
  	<resultMap type="Address" id="AddressResult">
  		<id property="addrId" column="addr_id"/>
		<result property="street" column="street"/>
		<result property="city" column="city"/>
		<result property="state" column="state"/>
		<result property="zip" column="zip"/>
		<result property="country" column="country"/>
  	</resultMap>
  	<!--查询指定的Address-->
  	<select id="selectAddressById" parameterType="int" resultMap="AddressResult">
  		select * from addresses where addr_id=#{addrId}
  	</select>
  	
</mapper>

  

 建立Student-Mapper.xml映射文件

 

<mapper namespace="com.mybatis3.mappers.StudentMapper">
	
	<resultMap type="Student" id="StudentResult">
		<id 	property="studId" column="stud_id"/>
		<result property="name" column="name" />
		<result property="email" column="email"/>
		<result property="phone" column="phone"/>
	</resultMap>
  	
  	<resultMap type="Student" id="StudentWithAddressExtResult" extends="StudentResult">
		<result property="address.addrId" column="addr_id"/>
		<result property="address.street" column="street"/>
		<result property="address.city" column="city"/>
		<result property="address.state" column="state"/>
		<result property="address.zip" column="zip"/>
		<result property="address.country" column="country"/>
	</resultMap>
	
  	<resultMap type="Student" id="StudentWithAddressNestedSelect">
		<id 	property="studId" column="stud_id"/>
		<result property="name" column="name"/>
		<result property="email" column="email"/>
		<association property="address" column="addr_id" select="com.mybatis3.mappers.AddressMapper.selectAddressById"/>
	</resultMap>
	
	<resultMap type="Student" id="StudentWithAddressNestedResultMap">
		<id 	property="studId" column="stud_id"/>
		<result property="name" column="name"/>
		<result property="email" column="email"/>
		<association property="address" javaType="Address">
			<id property="addrId" column="addr_id"/>
			<result property="street" column="street"/>
			<result property="city" column="city"/>
			<result property="state" column="state"/>
			<result property="zip" column="zip"/>
			<result property="country" column="country"/>
		</association>
	</resultMap>
	
	<select id="findAllStudents" resultMap="StudentResult">
    	select * from Students
  	</select>
        <select id="findStudentWithAddressExtResult" parameterType="int" resultMap="StudentWithAddressExtResult">
            SELECT STUD_ID, NAME, EMAIL, PHONE, A.ADDR_ID, STREET, CITY,  STATE, ZIP, COUNTRY
            FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON S.ADDR_ID=A.ADDR_ID
            WHERE STUD_ID=#{studId}
        </select>
  	
  	<select id="findStudentWithAddressNestedSelect" parameterType="int" resultMap="StudentWithAddressNestedSelect">
    	select * from Students where stud_id=#{studId}
  	</select>
  	  	  	
  	<select id="findStudentWithAddressNestedResultMap" parameterType="int" resultMap="StudentWithAddressNestedResultMap">
  		select stud_id, name, email,phone, a.addr_id, street, city, state, zip, country
  		FROM students s left outer join addresses a on s.addr_id=a.addr_id
		where stud_id=#{studId}
  	</select>
	
	  	
</mapper>

 

三种One-To-One映射的写法

 从Student-Mapper.xml中,可以看到,One-To-One的映射关系可以有三种写法

findStudentWithAddressExtResult
findStudentWithAddressNestedSelect
findStudentWithAddressNestedResultMap 

 

One-To-One映射:使用resultMap扩展(不推荐,了解即可)

 

1. resultMap定义

 

	<resultMap type="Student" id="StudentResult">  <!--定义Student表和Student之间的映射关系-->
		<id 	property="studId" column="stud_id"/>
		<result property="name" column="name" />
		<result property="email" column="email"/>
		<result property="phone" column="phone"/>
	</resultMap>
  	
  	<resultMap type="Student" id="StudentWithAddressExtResult" extends="StudentResult"> <!--扩展Student表和Student之间的映射关系-->
		<result property="address.addrId" column="addr_id"/> <!--property的写法使用.语法,类似OGNL表达式语言-->
		<result property="address.street" column="street"/> <!--column从哪里来的?这是在SQL语句中定义-->
		<result property="address.city" column="city"/>
		<result property="address.state" column="state"/>
		<result property="address.zip" column="zip"/>
		<result property="address.country" column="country"/>
	</resultMap>

 

2.SQL-Mapping定义

 

        <select id="findStudentWithAddressExtResult" parameterType="int" resultMap="StudentWithAddressExtResult">
            SELECT STUD_ID, NAME, EMAIL, PHONE, A.ADDR_ID, STREET, CITY,  STATE, ZIP, COUNTRY
            FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON S.ADDR_ID=A.ADDR_ID
            WHERE STUD_ID=#{studId}
        </select>

 

在SQL-Mapping中定义了StudentWithAddressExtResult定义的列名,这里看出,列名的定义,可以不关心是来自哪个表,MyBatis只是将得到的列名与属性名进行匹配,这样就有个问题:假如Student表和Address表都有一个相同的列name,如下所示,那么如果为两个NAME设置对应的值?

 

        <select id="findStudentWithAddressExtResult" parameterType="int" resultMap="StudentWithAddressExtResult">
            SELECT STUD_ID, NAME, EMAIL, PHONE, A.ADDR_ID, A.NAME, STREET, CITY,  STATE, ZIP, COUNTRY
            FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON S.ADDR_ID=A.ADDR_ID
            WHERE STUD_ID=#{studId}
        </select>

 

 

One-To-One映射:使用association + select属性(直观简洁,推荐用法)

1.resultMap定义

 

 	<resultMap type="Student" id="StudentWithAddressNestedSelect">
		<id 	property="studId" column="stud_id"/>
		<result property="name" column="name"/>
		<result property="email" column="email"/>
		<association property="address" column="addr_id" select="com.mybatis3.mappers.AddressMapper.selectAddressById"/>
	</resultMap

2. association定义

    assocation用于MyBatis定义1对1的关联关系

<association property="address" column="addr_id" select="com.mybatis3.mappers.AddressMapper.selectAddressById"/>

  

   com.mybatis3.mappers.AddressMapper.selectAddressById是一个查询操作标识符,定义在Address-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="com.mybatis3.mappers.AddressMapper">
	
  	<resultMap type="Address" id="AddressResult">
  		<id property="addrId" column="addr_id"/>
		<result property="street" column="street"/>
		<result property="city" column="city"/>
		<result property="state" column="state"/>
		<result property="zip" column="zip"/>
		<result property="country" column="country"/>
  	</resultMap>
  	
  	<select id="selectAddressById" parameterType="int" resultMap="AddressResult">
  		select * from addresses where addr_id=#{addrId}
  	</select>
  	
</mapper>

 

3. SQL查询语句

 

    <select id="findStudentById" parameterType="int" resultMap="StudentWithAddressNestedSelect">
    	select * from STUDENTS where stud_id=#{studId}
    </select>

 

 

 

One-To-One映射:使用association内部定义映射(无法重用,不推荐)

 

 1. resultMap定义

 

	<resultMap type="Student" id="StudentWithAddressNestedResultMap">
		<id 	property="studId" column="stud_id"/>
		<result property="name" column="name"/>
		<result property="email" column="email"/>
		<association property="address" javaType="Address">
			<id property="addrId" column="addr_id"/>
			<result property="street" column="street"/>
			<result property="city" column="city"/>
			<result property="state" column="state"/>
			<result property="zip" column="zip"/>
			<result property="country" column="country"/>
		</association>
	</resultMap>

 

 2. assocation内部定义映射关系,javaType的Address是一个类型别名,引用了Address类

 

		<association property="address" javaType="Address">
			<id property="addrId" column="addr_id"/>
			<result property="street" column="street"/>
			<result property="city" column="city"/>
			<result property="state" column="state"/>
			<result property="zip" column="zip"/>
			<result property="country" column="country"/>
		</association>

 

3. SQL语句的写法:

 

    <select id="selectStudentWithAddress" parameterType="int" resultMap="StudentWithAddressNestedResultMap">
  		select stud_id, name, email,phone, a.addr_id, street, city, state, zip, country
  		FROM STUDENTS s left outer join ADDRESSES a on s.addr_id=a.addr_id
		where stud_id=#{studId}
  	</select>

 

懒加载配置

要在第二种方式(assocation+select的方式)使用懒加载的方式,需要在MyBatis的主配置文件中配置懒加载选项:

 

<settings>
 <setting name="lazyLoadingEnabled" value="true"/>
 <setting name="aggressiveLazyLoading" value="false"/>
</settings> 

 

 

总结

 

1. 实现1对1映射的三种方式

 

  • resultMap继承, join查询,不能懒加载
  • assocation+select, 简单查询(N+1),可以懒加载
  • assocation+内嵌的resultMap映射,join查询,不能懒加载

2. 实际工作中,尽量使用assocation+select,加懒加载的方式

3. 工作中,数据库设计的不是那么的严格,比如不设置外键;对于这种关联关系的查询,使用多次的查询,每次执行简单语句,这是Bad Practices

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    java 之持久化框架mybatis3,

    MyBatis是一个流行的Java持久层框架,它简化了传统JDBC的编程方式,提供了丰富的数据映射功能,并且易于与各种数据库交互。MyBatis的核心思想是将SQL语句从Java代码中分离出来,通过映射配置文件,或注解的方式,将...

    mybatis自关联查询

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。在实际开发中,我们常常需要处理数据之间的关联关系,比如一对一、一对多、多对一、多对多等。本篇文章将重点讲解 MyBatis 中的自关联...

    数据持久化框架-MyBatis.html

    Mybatis是一款优秀的持久层框架,用于简化JDBC开发。 Mybatis官网:https://mybatis.org/mybatis-3/ Mybatis中文官网:https://mybatis.org/mybatis-3/zh/index.html 2、Mybatis的历史 Mybatis前身是Apache的一个...

    myBatis一对一和一对多

    MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。在实际的项目开发中,我们经常遇到一对一(One-to-One)和一对多(One-to-Many)的关系映射,这两种关系在数据库设计中非常常见。本主题将...

    [MyBatis] Java 持久化 (MyBatis 3 实现) (英文版)

    [Packt Publishing] Java 持久化 (MyBatis 3 实现) (英文版) [Packt Publishing] Java Persistence with MyBatis 3 (E-Book) ☆ 出版信息:☆ [作者信息] K. Siva Prasad Reddy [出版机构] Packt Publishing ...

    MyBatis3官方中文文档

    另外,MyBatis的映射文件是MyBatis框架中非常重要的一部分,它将SQL语句和映射的Java对象关联起来,是MyBatis中实现查询、插入、更新、删除等操作的关键。映射文件通常与接口紧密配合,通过命名空间和方法名的对应...

    mybatis持久化dao生成工具

    标题 "mybatis持久化dao生成工具" 涉及到的主要技术是MyBatis,一个流行的Java持久层框架,以及Freemarker,一个强大的模板引擎。这个工具旨在自动化Spring MVC框架中的DAO(数据访问对象)、Service层代码的生成,...

    Java Persistence With Mybatis 3

    《Java Persistence With Mybatis 3》是关于Java持久层框架Mybatis使用指南的一本书籍,它详细介绍了如何使用Mybatis进行数据库操作和数据持久化处理。Mybatis是一个支持定制化SQL、存储过程以及高级映射的持久层...

    四、Mybatis框架

    Mybatis是一个半自动的ORM持久化层框架,具有较高的sql灵活性,支持高级映射(一对一,一对多),动态sql、延迟SQL、延迟加载和缓存等特性,但它的数据库无关性较低。 Mybatis的特点: * 半自动的ORM框架,需要...

    Mybatis的课程管理系统数据持久化外文文献及翻译.zip

    Mybatis 是一款流行的Java持久层框架,用于简化数据库操作,特别是在复杂的SQL查询和对象关系映射(ORM)方面。在“Mybatis的课程管理系统数据持久化外文文献及翻译.zip”压缩包中,包含了关于Mybatis如何应用于课程...

    mybatis 框架和一些mybatis的依赖jar包

    MyBatis是一个优秀的Java持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的...

    Mybatis3帮助文档

    Mybatis 是一款流行的Java持久层框架,用于简化数据库操作,提供了强大的动态SQL支持。它将SQL语句与Java代码分离,使得开发人员可以更灵活地管理数据库查询,同时避免了传统的JDBC代码带来的繁琐和易出错的问题。...

    SpringBoot中mybatis表关联映射关系(一对多嵌套:结果方式)

    SpringBoot 中 MyBatis 表关联映射关系(一对多嵌套:结果方式) 在 SpringBoot 中,MyBatis 是一个非常流行的持久...最后,我们可以使用 MyBatis 来映射 Lesson 和 Stu 之间的一对多关联关系,实现数据的持久化操作。

    mybatis框架面试整理

    MyBatis是一个流行的Java持久层框架,它简化了数据库操作,使得开发人员能够更专注于SQL语句的编写,而无需处理大量的JDBC代码。在面试中,MyBatis经常成为讨论的重点,因为它在实际项目中的广泛应用。以下是对...

    官方比较完整的框架mybatis-3.4.6

    MyBatis是一个优秀的Java持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的...

    Mybatis框架

    Mybatis框架是一个强大的、灵活的Java持久层框架,它的出现极大地简化了数据库操作与Java对象之间的映射工作。Mybatis的核心在于SQL映射文件和SqlSessionFactory,它将传统的JDBC代码封装起来,使得开发者可以专注于...

    Mybatis框架基本介绍

    Mybatis是一个流行的持久层框架,它在企业级开发中被广泛应用。它主要用于解决与数据库交互时的映射问题,是一种半ORM(对象关系映射)框架。Mybatis通过使用简单的XML或注解的方式,将对象与数据库表进行映射,从而...

    封装通用的Spring3+Struts2+MyBatis3的CRUD+条件分页查询

    "封装通用的Spring3+Struts2+MyBatis3的CRUD+条件分页查询"是一个典型的企业级Web应用开发实践,它整合了三个主流的Java开源框架,即Spring、Struts2和MyBatis3,用于实现数据的创建(Create)、读取(Read)、更新...

Global site tag (gtag.js) - Google Analytics