MyBatis的关联映射

发布于:2025-03-01 ⋅ 阅读:(15) ⋅ 点赞:(0)

前言

    在实际开发中,对数据库的操作通常会涉及多张表,MyBatis提供了关联映射,这些关联映射可以很好地处理表与表,对象与对象之间的的关联关系。

一对一查询

步骤:

  1. 先确定表的一对一关系
  2. 确定好实体类,添加关联对象
  3. 使用resultMap定义好输出参数
  4. 编写sql语句
  5. 测试

    在MyBatis中,通过<association>元素来处理一对一的关联关系。<association>元素中的属性如下:

属性 说明
property 用于指定映射到的实体类对象的属性,与表字段一一对应
column 用于指定表中对应的字段
javaType 用于指定映射到实体对象的属性的类型
jdbcType 用于指定数据库中对应字段的类型
fetchType 用于指定关联查询时是否延迟加载。fetchType有lazy和eager两个属性值,默认为lazy延迟加载
select 用于引入嵌套查询的SQL语句,该属性用于关联映射的嵌套查询
autoMapping 用于指定是否自动映射
typeHandler 用于指定一个类型处理器
    <resultMap id="oneByOne" type="com.cc.User">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="gender" property="gender"/>
        <result column="age" property="age"/>
        <result column="address" property="address"/>
        <result column="email" property="email"/>
        <result column="qq" property="qq"/>
        <association property="login" javaType="com.cc.Login">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
        </association>
    </resultMap>

    <select id="findPassword" resultMap="oneByOne">
        select u.*,l.* from tb_userinfo u,tb_login l where u.name=l.username;
    </select>

   使用resultMap定义结果映射集,其中id标签用于映射数据库表中的主键字段,column为数据库的列名,property为java类的属性名。result用于映射普通字段。

    association标签用于映射关联对象的信息。property为关联对象的属性名,javaType为关联对象的Java类路径

一对多查询 

    在MyBatis中,通过<collection>元素来处理一对多关联关系。<collection>大多与<association>元素相同,还包含一个特殊属性ofType与javaType属性相对应,它用于指定实体类对象中集合类属性所包含的元素的类型。


示例:

    通过tb_userinfo表中的name值与tb_login中的username关联查询出两张表中的数据:

    将userinfo表与login两张表设计成两个实体类,并将login作为属性加入到userinfo中(也可以反过来):

public class User {
    private String id;
    private String name;
    private String gender;
    private int age;
    private String address;
    private String email;
    private String qq;
    private Login login;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Login getLogin() {
        return login;
    }

    public void setLogin(Login login) {
        this.login = login;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getQq() {
        return qq;
    }

    public void setQq(String qq) {
        this.qq = qq;
    }

    public User(String name, String gender, int age, String address, String email, String qq) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.address = address;
        this.email = email;
        this.qq = qq;
    }

    public User() {
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", email='" + email + '\'' +
                ", qq='" + qq + '\'' +
                ", login=" + login +
                '}';
    }
}





public class Login {
    private Integer id;
    private String username;
    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    public Login(){

    }

    public Login(String password, String username) {
        this.password = password;
        this.username = username;
    }

    @Override
    public String toString() {
        return "Login{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

    <resultMap id="order" type="com.cc.User">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="gender" property="gender"/>
        <result column="age" property="age"/>
        <result column="address" property="address"/>
        <result column="email" property="email"/>
        <result column="qq" property="qq"/>
        <collection property="login" ofType="com.cc.Login">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
        </collection>
    </resultMap>

    <select id="findPassword" resultMap="order">
        select u.*,l.* from tb_userinfo u,tb_login l where u.name=l.username;
    </select>

测试: 

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> u = userMapper.findPassword();
        for (User user:u){
            System.out.println(user);
        }

    在使用MyBatis嵌套查询进行MyBatis关联映射查询时,使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件mybatis.xml中的setting元素内进行配置。

        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>

多对多查询

    在数据库中,多对多的关联关系通常要使用一个中间表来维护。

    例如,要查询每个员工的职位,根据employee的id值在emp_posi找到对应的pid,再根据pid查找position职位的名称,如下图所示:

映射思路:

将position信息映射到employee中

在position添加属性List<EP> eps

mapper配置如下: 

    <resultMap id="map" type="com.cc.entity.Employee">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="position" column="position"/>
        <collection property="positions" ofType="com.cc.entity.Position">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <collection property="eps" ofType="com.cc.entity.EP">
                <id property="id" column="id"/>
                <result property="eId" column="emp_id"/>
                <result property="pId" column="posi_id"/>
            </collection>
        </collection>
    </resultMap>
    <select id="selectPosi" resultMap="map">
        select e.*,p.*,ep.*
            from employee e,position p,emp_posi ep
        where e.id=ep.emp_id and ep.posi_id=p.id;
    </select>

 查询结果如下:

发现查询出的职位错查成employee中的name值。出现该错误的原因是employee和position表使用了相同的列名name,解决方法就是给这些字段起别名