【持久化框架MyBatis3四】MyBatis3一对一关联查询
编程技术  /  houtizong 发布于 3年前   73
当两个实体具有1对1的对应关系时,可以使用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 STUDENTSINSERT INTO STUDENTS (STUD_ID,NAME,EMAIL,PHONE,DOB,BIO,PIC,ADDR_ID) VALUES (1,'Timothy','[email protected]','123-123-1234','1988-04-25',NULL,NULL,3), (2,'Douglas','[email protected]','789-456-1234','1990-08-15',NULL,NULL,4);
从上面的建表的sql中,可以看到,STUDENTS表通过外键ADDR_ID与ADDRESSES表建立1:1的映射关系
<?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>
<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_idwhere stud_id=#{studId} </select> </mapper>
从Student-Mapper.xml中,可以看到,One-To-One的映射关系可以有三种写法
findStudentWithAddressExtResultfindStudentWithAddressNestedSelectfindStudentWithAddressNestedResultMap
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>
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>
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_idwhere stud_id=#{studId} </select>
要在第二种方式(assocation+select的方式)使用懒加载的方式,需要在MyBatis的主配置文件中配置懒加载选项:
<settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/></settings>
1. 实现1对1映射的三种方式
2. 实际工作中,尽量使用assocation+select,加懒加载的方式
3. 工作中,数据库设计的不是那么的严格,比如不设置外键;对于这种关联关系的查询,使用多次的查询,每次执行简单语句,这是Bad Practices
请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!
技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成
网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];
文章归档
文章标签
友情链接