MyBatis关联映射:一对一

在实际项目开发中,经常存在一对一的关系,比如一个人只能有一个身份证,一个身份证只能给一个人使用,这就是一对一的关系,一对一关系推荐使用唯一主外键关系,即两张表使用外键关联关系,由于是一对一的关系,因此还需要给外键列增加unique唯一约束,下面我们就用一个简单示例来看看MyBatis怎么处理一对一的关系.
示例:OneToOneTest
1.建表
2.模型
public class Person implements Serializable
{
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    //人和身份证是一对一的关系
    private Card card;
    
    //无参数构造器
    public Person()
    {
        super();
    }
...
public class Card implements Serializable
{
    private Integer id;
    private String code;
    
    //无参数构造器
    public Card()
    {
        super();
    }
...
人和身份证是一对一的关系,即一个人只有一个身份证,在Person类中定义了一个card属性,该属性是一个Card类型,用来映射一对一的关联关系,表示这个人的身份证.
3.映射
CardMapper
<?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="org.fkit.mapper.CardMapper">
    <!-- 根据ID查询Card -->
    <select id="selectCardById" parameterType="int" resultType="org.fkit.domain.Card">
        SELECT * FROM tb_card WHERE ID=#{id}
    </select>
</mapper>

PersonMapper

<?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="org.fkit.mapper.PersonMapper">
    <!-- 根据ID查询Person 返回resultMap -->
    <select id="selectPersonById" parameterType="int" resultMap="personMapper">
        SELECT * FROM tb_person WHERE ID=#{id}
    </select>
    <!-- 映射Person对象 -->
    <resultMap id="personMapper" type="org.fkit.domain.Person">
        <id property="id" column="id" />
        <result property="name" column="NAME" />
        <result property="sex" column="SEX" />
        <result property="age" column="AGE" />
        <!-- 一对一关联映射association -->
        <association property="card" column="CARD_ID" select="org.fkit.mapper.CardMapper.selectCardById" javaType="org.fkit.domain.Card" />
    </resultMap>
</mapper>
在PersonMapper.xml中定义了一个<select…/>,其根据id查询Person信息,由于person类除了简单的属性id,name,sex和age之外,还有一个关联对象card,所以返回的是一个名为personMapper的resultMap.personMapper使用了<association…/>元素映射一对一的关联关系,select属性表示会使用column属性的card_id值作为参数执行CardMapper中定义的selectCardById查询对应的Card数据,查询出的数据将被封装到property表示的card对象当中.
之前的测试都是使用SqlSession对象调用insert,update和select方法进行测试.实际上,MyBatis官方手册建议通过Mapper接口代理对象访问MyBatis,该对象关联了SqlSession对象,开发者可以通过该对象直接调用方法操作数据库,下面定义一个mapper接口对象,需要注意的是,mapper接口对象的类型必须和之前的XML文件中的mapper的namespace一致,而方法名和参数也必须和XML文件中的<select…/>元素的id属性和parameterType属性一致.
4.Person接口
package org.fkit.mapper;
import org.fkit.domain.Person;
public interface PersonMapper
{
    /**
     * 根据ID查询Person
     * 方法名和参数必须与XML文件中的同名<select.../>一致
     * @param id
     * @return Person
     */
    Person selectPersonById(Integer id);
}

5.修改配置文件,添加刚建立的两个Mapper

<mappers>
    <mapper resource="org/fkit/mapper/UserMapper.xml" />
    <mapper resource="org/fkit/mapper/PersonMapper.xml" />
    <mapper resource="org/fkit/mapper/CardMapper.xml" />
</mappers>

6.控制器

@GetMapping("/mysql/OneToOneTest")
public void oneToOneTest()
{
    //获取SqlSession实例
    SqlSession sqlSession = FKSqlSessionFactory.getSqlSession();
    //获得Mapper接口代理对象
    PersonMapper pm = sqlSession.getMapper(PersonMapper.class);
    //直接调用接口方法,查询id为1的Person数据
    Person p = pm.selectPersonById(1);
    sqlSession.commit();
    sqlSession.close();
    System.out.println(p.getCard());
}

输出: