关联查询
association查询
实现一对一或多对一关联查询,就是主表与关联表的数据是一对一或多对一,例如员工为主表,关联部门表查询,1个员工在一个部门或者多个员工在1个部门。对应java类,1个部门类,1个员工类,员工类中有一个部门属性。
collection查询
就是主表与关联表的数据是一对多或多对多,例如部门为主表,员工关联表查询,一个部门有1个员工或者1个员工有多个员工。对应java类,1个部门类,1个员工类,部门类中有一个员工集合的属性。


下面的测试案例使用xml+接口的方式对数据库进行查询,分为八个文件:
主配置文件,
关联表Dept的实体类,关联表Dept的接口,关联表Dept的xml映射器,
主表Emp的实体类,主表Emp的接口,主表Emp的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>
<!-- 配置封装类的别名集,注意,配置别名要放在主配置文件开头 -->
<typeAliases>
<typeAlias type="com.test.day40.Emp" alias="Emp"/>
<typeAlias type="com.test.day40.Dept" alias="Dept"/>
</typeAliases>
<!-- 数据源环境配置 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 主配置文件引入映射器 -->
<mappers>
<mapper resource="com/test/day40/EmpMapper.xml" />
<mapper resource="com/test/day40/DeptMapper.xml" />
</mappers>
</configuration>
主表Emp的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">
<!-- 接口与xml映射器混合使用:mapper标签的namespace属性值是接口的全名(包名.接口)-->
<mapper namespace="com.test.day40.EmpMapper">
<!--
resultMap是配置emp类的属性与emp表的字段的对应关系
它可以不全都配置,只配置你需要的部分
比如说类有10个属性,值需要使用其中的5个属性与表的字段去对应,你就配置5个
-->
<resultMap id="empMap" type="Emp">
<!-- 配置emp类的属性与emp表的字段的对应关系 -->
<id property="id" column="id"/>
<result property="eName" column="e_name"/>
<result property="sex" column="sex"/>
<result property="eNo" column="e_no"/>
<result property="dId" column="d_id"/>
</resultMap>
<!--
resultMap可以配置多个,但是id不能重复
为了防止重复的配置,可以继承resultMap继承其他的resultMap
-->
<resultMap id="empAndDeptMap" type="Emp" extends="empMap">
<!--
在子的resultMap中重新配置父的属性映射,
子的映射可以覆盖父的映射,但是只是在子的resultMap生效,不影响父的resultMap
在当前来说,就是empAndDeptMap中的id属性映射eid字段
但是empMap中,依然还是id属性映射id字段
-->
<id property="id" column="eid"/>
<!--
association标签实现一对一或多对一关联查询,
就是主表与关联表的数据是一对一或多对一,
例如员工为主表,关联部门表查询,1个员工在一个部门或者多个员工在1个部门。
对应java类,1个部门类,1个员工类,员工类中有一个部门属性。
以SQL语句为例(一对一或多对一):SELECT * FROM emp e LEFT JOIN dept d ON e.d_id = d.id
property="dept",emp类的dept属性名
column="id",根据关联查询条件ON e.d_id = d.id,dept表与emp的关联字段是dept表的id字段
javaType="Dept",emp类的dept属性的类型是Dept类
resultMap="com.test.day40.DeptMapper.deptMap",emp类的dept属性对应的resultMap,
如果这个resultMap不在当前的xml配置文件中,值就要写成resultMap所在的配置文件的namespace.resultMap的id
例如:id是deptMap的resultMap在namespace是com.test.day40.DeptMapper的xml配置文件中,resultMap="com.test.day40.DeptMapper.deptMap"
-->
<association property="dept" column="id" javaType="Dept" resultMap="com.test.day40.DeptMapper.deptMap"/>
</resultMap>
<!--
在关联查询中,哪个是主表,就把这个查询写在哪个的xml配置文件中
如果在查询个过程中,查询的字段出现相同的字段名,我们要给其中一个加别名,保证没有重名的字段
加了别名的字段,要在resultMap中修改属性与字段的映射
-->
<select id="select" resultMap="empAndDeptMap">
SELECT
e.id eid,e.e_name,e.sex,e.e_no,e.d_id,d.id,d.d_name,d.d_desc,d.d_no
FROM emp e LEFT JOIN dept d ON e.d_id = d.id
</select>
</mapper>
主表Emp的接口
package com.test.day40;
import java.util.List;
//接口和映射器混合使用:方法名与xml映射器中的id值对应
public interface EmpMapper {
public List<Emp> select();
}
主表Emp的测试实体类
package com.test.day40;
import java.io.Serializable;
public class Emp implements Serializable{
private static final long serialVersionUID = 1L;
public Integer id;
public String eName;
public String sex;
public String eNo;
public Integer dId;
public Dept dept;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String geteName() {
return eName;
}
public void seteName(String eName) {
this.eName = eName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String geteNo() {
return eNo;
}
public void seteNo(String eNo) {
this.eNo = eNo;
}
public Integer getdId() {
return dId;
}
public void setdId(Integer dId) {
this.dId = dId;
}
@Override
public String toString() {
return "emp[id=" + id + ",eName=" + eName + ",sex=" + sex + ",eNo=" + eNo + ",dId"
+ dId + ",dept=" + dept + "]";
}
}
关联表Dept的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">
<!-- 接口与xml映射器混合使用:mapper标签的namespace属性值是接口的全名(包名.接口)-->
<mapper namespace="com.test.day40.DeptMapper">
<resultMap id="deptMap" type="Dept">
<!-- 配置Dept类的属性与Dept表的字段的对应关系 -->
<id property="id" column="id"/>
<result property="dName" column="d_name"/>
<result property="dDesc" column="d_desc"/>
<result property="dNo" column="d_no"/>
</resultMap>
<resultMap id="deptAndEmpMap" type="Dept" extends="deptMap">
<!-- 覆盖父的resultMap关于id的映射配置 -->
<id property="id" column="did"/>
<!--
基于collection查询(一对多),
就是主表与关联表的数据是一对多或多对多,例如部门为主表,员工关联表查询,
一个部门有1个员工或者1个员工有多个员工。
以SQL语句为例(一对多):SELECT * FROM dept d LEFT JOIN emp e ON e.d_id = d.id
collection标签,是用来配置实体类的集合型的属性
property="emps",实体类的集合型的属性的属性名
ofType="Emp",实体类的集合型的属性的泛型
resultMap="com.test.day40.EmpMapper.empMap",实体类的集合型的属性的泛型对应resultMap
值就要写成resultMap所在的配置文件的namespace.resultMap的id
-->
<collection property="emps" ofType="Emp" resultMap="com.test.day40.EmpMapper.empMap"/>
</resultMap>
<select id="select" resultMap="deptAndEmpMap">
SELECT
e.id,e.e_name,e.sex,e.e_no,e.d_id,d.id did,d.d_name,d.d_desc,d.d_no
FROM dept d LEFT JOIN emp e ON e.d_id = d.id
</select>
</mapper>
关联表Dept的接口
package com.test.day40;
import java.util.List;
//接口和映射器混合使用:方法名与xml映射器中的id值对应
public interface DeptMapper {
public List<Dept> select();
}
关联表Dept的测试实体类
package com.test.day40;
import java.io.Serializable;
import java.util.List;
public class Dept implements Serializable{
private static final long serialVersionUID = 1L;
public Integer id;
public String dName;
public String dNo;
public String dDesc;
public List<Emp> emps;
public List<Emp> getEmps() {
return emps;
}
public void setEmps(List<Emp> emps) {
this.emps = emps;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getdName() {
return dName;
}
public void setdName(String dName) {
this.dName = dName;
}
public String getdNo() {
return dNo;
}
public void setdNo(String dNo) {
this.dNo = dNo;
}
public String getdDesc() {
return dDesc;
}
public void setdDesc(String dDesc) {
this.dDesc = dDesc;
}
@Override
public String toString() {
return "[id=" + id + ",dName=" + dName + ",dNo=" + dNo + ",dDesc=" + dDesc + ",emps=" + emps +"]";
}
}
调用程序:接口和映射器混合使用
public class XmlAndInMapperTest {
public static void main(String[] args) {
Reader reader = null;
SqlSessionFactory sqlSessionFactory = null;
SqlSession session = null;
try{
//加载主配置文件,主配置文件中有数据库连接相关信息,还有映射器的相关信息
//参数是主配置文件的路径,我们的主配置文件是在跟路径下,所以直接写文件名就可以
reader = Resources.getResourceAsReader("myBatis-config.xml");
//创建SqlSessionFactory工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//得到SqlSession对象,这个对象是操作映射器的对象
session = sqlSessionFactory.openSession();
//操作接口与xml混合映射器:getMapper(接口的class).调用的方法
// List<Emp> list = session.getMapper(EmpMapper.class).select();//测试association查询
List<Dept> list = session.getMapper(DeptMapper.class).select();//测试collection查询
System.out.println(list);
//提交session
session.commit();
}catch(Exception e){
//如果发生异常回滚session
session.rollback();
}finally{
//关闭资源
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
session.close();
}
}
}