Mybatis映射-8
一.一对多关联
1 一对多广泛存在于实际应用中,部门和员工,县区和街道
2 一对多的分类,从方向来分可以分为
-
单向一对多:只在一的一方配置多方的关联
-
单向多对一:只在多的一方配置一方的关联
-
双向一对多:在两方都配置
3.mybaits中配置一对多
在mybatis配置一对多的方式两种
3.1 嵌套映射的配置方式
案例:配置单向一对多
1)数据库表结构
|
CREATE TABLE `dept` ( `DEPTNO` INT(2) NOT NULL, `DNAME` VARCHAR(14) DEFAULT NULL, `LOC` VARCHAR(13) DEFAULT NULL, PRIMARY KEY (`DEPTNO`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO `dept` VALUES ('10', 'ACCOUNTING', 'NEW YORK'); INSERT INTO `dept` VALUES ('20', 'RESEARCH', 'DALLAS'); INSERT INTO `dept` VALUES ('30', 'SALES', 'CHICAGO'); INSERT INTO `dept` VALUES ('40', 'OPERATIONS', 'BOSTON'); DROP TABLE IF EXISTS `emp`; CREATE TABLE `emp` ( `EMPNO` INT(4) NOT NULL, `ENAME` VARCHAR(10), `JOB` VARCHAR(9), `MGR` INT(4), `HIREDATE` DATE, `SAL` INT(7), `COMM` INT(7), `DEPTNO` INT(2), PRIMARY KEY (`EMPNO`), KEY `FK_DEPTNO` (`DEPTNO`), CONSTRAINT `FK_DEPTNO` FOREIGN KEY (`DEPTNO`) REFERENCES `dept` (`DEPTNO`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO `emp` VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800', NULL, '20'); INSERT INTO `emp` VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30'); INSERT INTO `emp` VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30'); INSERT INTO `emp` VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', NULL, '20'); INSERT INTO `emp` VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30'); INSERT INTO `emp` VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', NULL, '30'); INSERT INTO `emp` VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', NULL, '10'); INSERT INTO `emp` VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000', NULL, '20'); INSERT INTO `emp` VALUES ('7839', 'KING', 'PRESIDENT', NULL, '1981-11-17', '5000', NULL, '10'); INSERT INTO `emp` VALUES ('7844', 'TURNER', 'SALESMAN','7698', '1981-09-08', '1500', '0', '30'); INSERT INTO `emp` VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23', '1100', NULL, '20'); INSERT INTO `emp` VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', NULL, '30'); INSERT INTO `emp` VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', NULL, '20'); INSERT INTO `emp` VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', NULL, '10'); |
2)创建实体对象
|
@Data public class Dept { private Byte deptno; private String dname; private String loc; private List<Emp> emps; } |
|
@Data public class Emp { private Short empno; private String ename; private String job; private Short mgr; private Date hiredate; private Float sal; private Float comm; } |
3)编写接口
|
public interface DeptMapper { public Dept selectDeptByNo(Byte deptno); } |
4)映射文件
|
<?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.woniuxy.dao.DeptMapper"> <resultMap id="detpMap" type="dept"> <id property="deptno" column="deptno"></id> <result property="dname" column="dname"></result> <result property="loc" column="loc"></result> <!-- collection:在一方配置多方关联的节点,常用的属性如下 |- property: 关联对象的属性名 |-ofType:表示的是集合中的元素的类型,可以是类全名,也可以是别名 --> <collection property="emps" ofType="Emp"> <id property="empno" column="empno"></id> <result property="ename" column="ename"></result> <result property="job" column="job"></result> <result property="mgr" column="mgr"></result> <result property="hiredate" column="hiredate"></result> <result property="sal" column="sal"></result> <result property="comm" column="comm"></result> </collection> </resultMap> <select id="selectDeptByNo" parameterType="byte" resultMap="detpMap"> SELECT * FROM dept d INNER JOIN emp e ON d.deptno=e.deptno WHERE d.deptno=#{deptno} </select> </mapper> |
5)编写测试
|
package com.woniuxy; import static org.junit.Assert.assertTrue; import com.woniuxy.dao.DeptMapper; import com.woniuxy.pojo.Dept; import com.woniuxy.pojo.Emp; import com.woniuxy.util.MyBatisUtil; import org.apache.ibatis.session.SqlSession; import org.apache.log4j.Logger; import org.junit.Test; import java.util.List; /** * Unit test for simple App. */ public class AppTest { private Logger logger= Logger.getLogger(AppTest.class); @Test public void test1() { SqlSession sqlSession= MyBatisUtil.crateSqlSession(); DeptMapper deptMapper=sqlSession.getMapper(DeptMapper.class); Dept dept=deptMapper.selectDeptByNo((byte)10); logger.info("部门信息:"+dept.getDeptno()+" "+dept.getDname()+" "+dept.getLoc()); List<Emp> emps=dept.getEmps(); if(emps!=null&& !emps.isEmpty()){ logger.info("该部门有"+emps.size()+"个员工"); logger.info("员工信息如下:"); for(Emp emp:emps){ logger.info(emp.getEmpno()+" "+emp.getEname() +" "+emp.getJob()+" "+emp.getMgr() +" "+emp.getHiredate() +" "+emp.getSal()+" "+emp.getComm()); } } MyBatisUtil.closeSqlSession(sqlSession); } } |
3.2分步查询的配置一对多的方式【重点掌握】
1)编写实体
|
@Data public class Emp { private Short empno; private String ename; private String job; private Short mgr; private Date hiredate; private Float sal; private Float comm; } |
|
@Data public class Dept { private Byte deptno; private String dname; private String loc; private List<Emp> emps; } |
2)编写接口
|
public interface DeptMapper { /** * 通过部门编号查询部门对象 */ public Dept selectDeptByDeptno(Byte deptno); } |
|
public interface EmpMapper { /** * 通过部门编号查询该部门中所有员工信息 */ public List<Emp> selectEmpsByDeptno(Byte deptno); } |
3)编写映射文件
|
<?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.woniuxy.dao.DeptMapper"> <resultMap id="deptMap" type="dept"> <id property="deptno" column="deptno"></id> <result property="dname" column="dname"></result> <result property="loc" column="loc"></result> <!-- collection:完成一对多的配置,用于集合设置,常用的属性 |- property:关联集合对象的属性名 |-select:完成分步查询的SQL语句 |-column:传递的参数,是dept表的主键 --> <collection property="emps" select="com.woniuxy.dao.EmpMapper.selectEmpsByDeptno" column="deptno"> </collection> </resultMap> <select id="selectDeptByDeptno" parameterType="Byte" resultMap="deptMap"> SELECT DEPTNO,DNAME,LOC FROM DEPT WHERE DEPTNO=#{deptno} </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="com.woniuxy.dao.EmpMapper"> <select id="selectEmpsByDeptno" parameterType="Byte" resultType="emp"> SELECT * FROM EMP WHERE DEPTNO=#{deptno} </select> </mapper> |
4)编写测试
|
package com.woniuxy; import static org.junit.Assert.assertTrue; import com.woniuxy.dao.DeptMapper; import com.woniuxy.pojo.Dept; import com.woniuxy.pojo.Emp; import com.woniuxy.util.MyBatisUtil; import org.apache.ibatis.session.SqlSession; import org.apache.log4j.Logger; import org.junit.Test; import java.util.List; public class AppTest { private Logger logger=Logger.getLogger(AppTest.class); @Test public void test1() { SqlSession sqlSession= MyBatisUtil.crateSqlSession(); DeptMapper deptMapper=sqlSession.getMapper(DeptMapper.class); Dept dept=deptMapper.selectDeptByDeptno((byte)10); logger.info("部门信息:"+dept.getDeptno()+" "+dept.getDname()+" "+dept.getLoc()); List<Emp> emps=dept.getEmps(); if(emps!=null&& !emps.isEmpty()){ logger.info("该部门有"+emps.size()+"个员工"); logger.info("员工信息如下:"); for(Emp emp:emps){ logger.info(emp.getEmpno()+" "+emp.getEname() +" "+emp.getJob()+" "+emp.getMgr() +" "+emp.getHiredate() +" "+emp.getSal()+" "+emp.getComm()); } } MyBatisUtil.closeSqlSession(sqlSession); } } |

通过控制台信息的输出会发现,此时属于立即加载
在mybatis-config.xml文件中配置延迟加载
|
<setting name="lazyLoadingEnabled" value="true"></setting> <setting name="aggressiveLazyLoading" value="false"></setting> |

当然也可以在collection节点中通过fetchType进行设置
为了演示fetchType是否能做延迟加载,在DeptMapper.xml文件中设置

此时控制台输出告诉我们,我们现在是立即加载,所以可以证明在SQL映射文件中通过fetchType设置是否要延迟加载优先级要高于mybatis配置文件中通过setting运行时的设置。

作业:完成如下操作

设计数据库表,使用mybatis完成一对多的关系
客户-----1:n------>联系人
客户-----1:n--------->交往记录
客户-----1:n---------->订单
订单-----1:n----------->订单明细

浙公网安备 33010602011771号