一对一也就是 A 表的一条记录对应 B 表的一条记录, 下面的测试数据中, 从 employee 表来看, 一个员工对应一个部门, 是一对一关系, 如果从部门角度来看, 则是一对多的关系, 一个部门对应多个员工, 本节主要研究一对一的关系.
1, 数据表建立
新建数据表 department, 有两个字段, 插入两条数据如下:
id | dept_name |
1 | CIA |
2 | FSB |
新建数据表 employee, 有三个字段, 其中 dept_id 是外键, 关联 department 表的主键 id. 插入数据如下:
id | last_name | dept_id |
1 | Tom | 1 |
2 | Jerry | 2 |
3 | Neo | 1 |
4 | Cypher | 2 |
2, 新建 maven 工程, 添加依赖, 主要是 mybatis 和 MySQL
- <dependencies>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.4.6</version>
- </dependency>
- <dependency>
- <groupId>MySQL</groupId>
- <artifactId>MySQL-connector-java</artifactId>
- <version>5.1.47</version>
- </dependency>
- </dependencies>
3, 编写数据库表对应的实体.
对于 department 表, 对应实体如下:
- package com.yefengyu.mybatis.entity;
- public class Department
- {
- private Integer id;
- private String deptName;
- public Integer getId()
- {
- return id;
- }
- public void setId(Integer id)
- {
- this.id = id;
- }
- public String getDeptName()
- {
- return deptName;
- }
- public void setDeptName(String deptName)
- {
- this.deptName = deptName;
- }
- @Override
- public String toString()
- {
- return "Department{" +
- "id=" + id +
- ", deptName='" + deptName + '\'' +
- '}';
- }
- }
对于 employee 表, 实体如下, 注意在 Employee 实体中把外键直接变成对于 Department 对象的引用.
- package com.yefengyu.mybatis.entity;
- public class Employee
- {
- private Integer id;
- private String lastName;
- private Department department;
- public Integer getId()
- {
- return id;
- }
- public void setId(Integer id)
- {
- this.id = id;
- }
- public String getLastName()
- {
- return lastName;
- }
- public void setLastName(String lastName)
- {
- this.lastName = lastName;
- }
- public Department getDepartment()
- {
- return department;
- }
- public void setDepartment(Department department)
- {
- this.department = department;
- }
- @Override
- public String toString()
- {
- return "Employee{" +
- "id=" + id +
- ", lastName='" + lastName + '\'' +
- ", department=" + department +
- '}';
- }
- }
4, 编写 mapper 接口
- package com.yefengyu.mybatis.mapper;
- import com.yefengyu.mybatis.entity.Employee;
- public interface EmployeeMapper
- {
- Employee getEmployee(Integer id);
- }
根据员工 ID 查询员工信息和部门信息
5, 编写 mapper 映射文件(本节重点)
一对一查询 mapper 文件有三种编写方式, 分别是:
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.yefengyu.mybatis.mapper.EmployeeMapper">
- <resultMap id="employee" type="com.yefengyu.mybatis.entity.Employee">
- <id column="id" property="id"/>
- <result column="last_name" property="lastName"/>
- <result column="d_id" property="department.id"/>
- <result column="dept_name" property="department.deptName"/>
- </resultMap>
- <select id="getEmployee" resultMap="employee">
- select e.id id, e.last_name last_name, e.dept_id dept_id, d.id d_id,d.dept_name dept_name
- from employee e, department d
- where e.id = #{id} and e.dept_id = d.id
- </select>
- </mapper>
2,association 嵌套结果集
<?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.yefengyu.mybatis.mapper.EmployeeMapper">
- <!--
- 使用 association 定义关联的单个对象的封装规则;
- -->
- <resultMap id="employee" type="com.yefengyu.mybatis.entity.Employee">
- <id column="id" property="id"/>
- <result column="last_name" property="lastName"/>
- <!-- association 可以指定联合的 javaBean 对象
- property="department": 指定哪个属性是联合的对象
- javaType: 指定这个属性对象的类型[不能省略]
- -->
- <association property="department" javaType="com.yefengyu.mybatis.entity.Department">
- <id column="d_id" property="id"/>
- <result column="dept_name" property="deptName"/>
- </association>
- </resultMap>
- <select id="getEmployee" resultMap="employee">
- select e.id id, e.last_name last_name, e.dept_id dept_id, d.id d_id,d.dept_name dept_name
- from employee e, department d
- where e.id = #{id} and e.dept_id = d.id
- </select>
- </mapper>
3,association 分步查询法
1)首先需要创建一个关于 department 的接口
- package com.yefengyu.mybatis.mapper;
- import com.yefengyu.mybatis.entity.Department;
- public interface DepartmentMapper
- {
- public Department getDeptById(Integer id);
- }
2)其次编写该接口的映射文件
<?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.yefengyu.mybatis.mapper.DepartmentMapper">
- <select id="getDeptById" resultType="com.yefengyu.mybatis.entity.Department">
- select id,dept_name from department where id = #{id}
- </select>
- </mapper>
3)现在定义一个查询 employee 的接口(级联属性法和 association 嵌套结果集测试时已经建立该接口)
- package com.yefengyu.mybatis.mapper;
- import com.yefengyu.mybatis.entity.Employee;
- public interface EmployeeMapper
- {
- Employee getEmployee(Integer id);
- }
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.yefengyu.mybatis.mapper.EmployeeMapper">
- <resultMap id="employee" type="com.yefengyu.mybatis.entity.Employee">
- <id column="id" property="id"/>
- <result column="last_name" property="lastName"/>
- <!-- association 定义关联对象的封装规则
- select: 表明当前属性是调用 select 指定的方法查出的结果
- column: 指定将哪一列的值传给这个方法
- 流程: 使用 select 指定的方法 (传入 column 指定的这列参数的值) 查出对象, 并封装给 property 指定的属性
- -->
- <association property="department"
- select="com.yefengyu.mybatis.mapper.DepartmentMapper.getDeptById"
- column="dept_id">
- </association>
- </resultMap>
- <select id="getEmployee" resultMap="employee">
- select * from employee where id = #{id}
- </select>
- </mapper>
延迟加载:
每次查询 Employee 对象的时候, 都将部门信息一起查询出来. 但是想要部门信息在我们使用的时候再去查询, 如果不需要就不查询, 怎么实现? 分步查询的基础上加两个配置:
- <!-- 显示的指定每个我们需要更改的配置的值, 即使他是默认的. 防止版本更新带来的问题 -->
- <setting name="lazyLoadingEnabled" value="true" />
- <setting name="aggressiveLazyLoading" value="false" />
Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载, association 指的就是一对一, collection 指的就是一对多查询.
6, 新建一个 mybatis 全局配置文件, 详细信息见官网
<?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>
- <settings>
- <setting name="mapUnderscoreToCamelCase" value="true"/>
- <setting name="logImpl" value="STDOUT_LOGGING" />
- </settings>
- <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://127.0.0.1:3306/mybatis?characterEncoding=utf8&allowMultiQueries=true"/>
- <property name="username" value="root"/>
- <property name="password" value="123456"/>
- </dataSource>
- </environment>
- </environments>
- <mappers>
- <mapper resource="mapper/PersonMapper.xml"/>
- <mapper resource="mapper/EmployeeMapper.xml"/>
- <mapper resource="mapper/DepartmentMapper.xml"/>
- </mappers>
- </configuration>
7, 测试
通用测试代码:
- public static void main(String[] args)
- throws IOException
- {
- InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
- SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
- SqlSession sqlSession = sqlSessionFactory.openSession();
- try
- {
- EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
- Employee employee = mapper.getEmployee(1);
- System.out.println(employee);
- }
- finally
- {
- sqlSession.close();
- }
- }
准对于延迟加载的特殊测试, 对于上面测试代码, 如果只打印员工名
System.out.println(employee.getLastName());
那么不会查询部门表
- Created connection 1776957250.
- Setting autocommit to false on JDBC Connection [[email protected]]
- ==> Preparing: select * from employee where id = ?
- ==> Parameters: 1(Integer)
- <== Columns: id, last_name, dept_id
- <== Row: 1, tom, 1
- <== Total: 1
- tom
- Resetting autocommit to true on JDBC Connection [[email protected]]
- Closing JDBC Connection [[email protected]]
- Returned connection 1776957250 to pool.
如果打印部门相关信息, 例如通用测试的代码(由于实体都重写了 toString 方法, 因此打印 employee 的时候也打印了 department, 所以也是使用了部门信息), 此时的日志为:
- Created connection 1776957250.
- Setting autocommit to false on JDBC Connection [[email protected]]
- ==> Preparing: select * from employee where id = ?
- ==> Parameters: 1(Integer)
- <== Columns: id, last_name, dept_id
- <== Row: 1, tom, 1
- <== Total: 1
- ==> Preparing: select id,dept_name from department where id = ?
- ==> Parameters: 1(Integer)
- <== Columns: id, dept_name
- <== Row: 1, A
- <== Total: 1
- Employee{
- id=1, lastName='tom', department=Department{
- id=1, deptName='A'
- }
- }
- Resetting autocommit to true on JDBC Connection [[email protected]]
- Closing JDBC Connection [[email protected]]
- Returned connection 1776957250 to pool.
来源: http://www.bubuko.com/infodetail-3094884.html