14、Mybatis之一对一关联查询

例如一个人有一部手机,每个品牌手机的价格不同,下面通过两个表来表示这个时间,PERSON表和PHONE表。

PERSON表:
这里写图片描述

PHONE表:
这里写图片描述

两个表中通过phone_brand字段对应,首先在PERSON表中通过id查询出某人拥有的手机品牌phone_brand,然后在PHONE表中通过手机品牌phone_brand查出价格。实现两个表的一对一关联查询。

下面演示如何用mybatis实现此两个表一对一的关联查询。
首先建立两个表对应的实体类bean。

Person类:

package com.lzj.mybaits.bean;

public class Person {

    private int id;
    private String name;
    private Phone phone;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Phone getPhone() {
        return phone;
    }
    public void setPhone(Phone phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", phone=" + phone + "]";
    }

}

Phone类:

package com.lzj.mybaits.bean;

public class Phone {

    private String brand;
    private float price;

    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Phone [brand=" + brand + ", price=" + price + "]";
    }

}

然后建立Dao接口,对应于Mybatis中mapper文件的查询语句。

public interface PersonDao {

    public Person getPerson(int id);

}

下面分三种方式实现一对一级联查询

方式一:

把联表中的字段用不同的别名命名区分,然后把别名通过resultMap 映射成类中对应的属性。

<mapper namespace="com.lzj.mybatis.dao.PersonDao">

    <!-- 一对一的级联查询,级联属性的方式 -->
    <!--column中为字段的别名;propert对应Person类中属性-->
    <resultMap type="com.lzj.mybaits.bean.Person" id="personResult">
        <id column="id" property="id" />
        <result column="name" property="name" />
        <!--phone为Person类中的一个对象属性,通过“对象.”的形式映射到Phone类的对象属性中-->
        <result column="pbrand" property="phone.brand" />
        <result column="price" property="phone.price" />
    </resultMap>

    <!--注意字段的别名最好要定义成不同的,以便在resultMap映射清晰-->
    <select id="getPerson" parameterType="int" resultMap="personResult2">
        SELECT
        ps.id, ps.name, ps.phone_brand brand,
        ph.phone_brand pbrand,
        ph.phone_price price FROM PERSON ps, PHONE ph
        WHERE
        ps.phone_brand=ph.phone_brand AND ps.id=#{id}
    </select>

</mapper>

测试方法为:

    public static void testGetPseron(){
        String resource = "conf.xml";
        InputStream in = MybaitsTest.class.getClassLoader().getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);   
        SqlSession session = factory.openSession();
        PersonDao personDao = session.getMapper(PersonDao.class);
        Person person = personDao.getPerson(1);
        System.out.println(person);
        session.close();
    }

运行测试方法,输出结果

Person [id=1, name=lzj, phone=Phone [brand=iphone, price=5000.0]]

方式二:

一对一级联查询,用association的方式

<mapper namespace="com.lzj.mybatis.dao.PersonDao">

    <resultMap type="com.lzj.mybaits.bean.Person" id="personResult2">
        <!--column中为字段的别名;propert对应Person类中属性-->
        <id column="id" property="id" />
        <result column="name" property="name" />
        <!--Person类中最后一个对象属性为phone,通过property指定;通过javaType指定phone的类型;-->
        <association property="phone" javaType="com.lzj.mybaits.bean.Phone">
            <!--column中为字段的别名;propert对应Phone类中属性-->
            <result column="pbrand" property="brand" />
            <result column="price" property="price" />
        </association>


    </resultMap>

    <select id="getPerson" parameterType="int" resultMap="personResult2">
        SELECT
        ps.id, ps.name, ps.phone_brand brand,
        ph.phone_brand pbrand,
        ph.phone_price price FROM PERSON ps, PHONE ph
        WHERE
        ps.phone_brand=ph.phone_brand AND ps.id=#{id}
    </select>

</mapper>

测试方法同上,运行测试方法,结果同上。

方式三:

通过association实现分布查询
首先按照id查询PERSON的信息;
然后按照PERSON信息中的phone_brand去查询PHONE信息;
最后把查到的PHONE信息设置到PERSON信息中。

1、首先按照id查询PERSON的信息
Dao接口

package com.lzj.mybatis.dao;
import com.lzj.mybaits.bean.Person;
public interface PersonDao {
    public Person getByStepPerson(int id);  
}

sql的映射mapper文件PsersonDaoMapper.xml:

<mapper namespace="com.lzj.mybatis.dao.PersonDao">

    <!--3.把查询到的PHONE信息设置到PERSON信息中-->
    <resultMap type="com.lzj.mybaits.bean.Person" id="resultByStep">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <!--phone的信息通过传入字段phone_brand来查询com.lzj.mybatis.dao.PhoneDao.getPhone方法获得-->
        <association property="phone" select="com.lzj.mybatis.dao.PhoneDao.getPhone"
            column="phone_brand"></association>
    </resultMap>

    <!--1.首先根据id查询PERSON的信息-->
    <select id="getByStepPerson" resultMap="resultByStep">
        select * from PERSON where id=#{id}
    </select>

</mapper>

2、然后按照PERSON信息中的phone_brand去查询PHONE信息
PHONE的Dao接口:

package com.lzj.mybatis.dao;
import com.lzj.mybaits.bean.Phone;
public interface PhoneDao {
    public Phone getPhone(String brand);
}

sql的映射mapper文件PhoneMapper.xml:

<mapper namespace="com.lzj.mybatis.dao.PhoneDao">
    <select id="getPhone" resultType="com.lzj.mybaits.bean.Phone">
        select phone_brand brand, phone_price price from PHONE where phone_brand=#{brand}
    </select>
</mapper>

测试方法同上,输出结果同上。

方法四:

对于方法三分布查询中,先查询PERSON的sql语句,然后再查询PHONE的sql语句。在联合查询中,有时我们只需要联合查询的部分数据,就没必要进行全部的sql语句查询。例如在方法三的联合查询中,只需要PERSON表中的name信息,此时可以不用查询PHONE表。可以在mybatis的配置文件中设置为懒加载,当用到时候执行相应的SQL语句。
配置文件中设置如下:

    <settings>
        <!--lazyLoadingEnabled设置为false,表示需要的时候才执行sql-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--aggressiveLazyLoading设置为true表示一次性执行联合查询中的所有sql,所以此地设置为false,不执行一次性查询--->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

对于方法三种的案例,如果测试方法改为

    public static void testGetPersonByStep(){
            String resource = "conf.xml";
            InputStream in = MybaitsTest.class.getClassLoader().getResourceAsStream(resource);
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);   
            SqlSession session = factory.openSession();
            PersonDao personDao = session.getMapper(PersonDao.class);
            Person person = personDao.getByStepPerson(2);
            /*只打印了name信息,此时只执行查询PERSON的SQL的语句就够了,查询PHONE的SQL语句没有执行*/
            System.out.println(person.getName());
            session.close();
    }

如果把上面的打印语句改为:

System.out.println(person.getPhone());

表示需要person中的phone信息,此时再继续执行查询PHONE的sql语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值