07 Mybatis的多表查询1----1对多和多对1

1.表与表之间的关系及其举例

表之间的关系有4种:一对多、多对一、一对一、多对多。
举例:
  (1)用户和订单就是一对多

    一个用户可以下多个订单
  (2)订单和用户就是多对一
    多个订单属于同一个用户

  (3)人和身份证号就是一对一
    一个人只能有一个身份证号
    一个身份证号只能属于一个人

  (4)老师和学生之间就是多对多
    一个学生可以被多个老师教过
    一个老师可以交多个学生

2.mybatis中的多表查询
示例:用户和账户
  一个用户可以有多个账户
  一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
  1、建立两张表:用户表,账户表
    让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
  2、建立两个实体类:用户实体类和账户实体类
    让用户和账户的实体类能体现出来一对多的关系
  3、建立两个配置文件
    用户的配置文件
    账户的配置文件
  4、实现配置:
    当我们查询用户时,可以同时得到用户下所包含的账户信息
    当我们查询账户时,可以同时得到账户的所属用户信息

3.操作案例

(1)案例1

查询所有查询所有账户,及其用户名和地址信息(逻辑为:账户表account-----》用户信息表user)

<1>对数据库表Account对应的实体类Account.java进行改造,加入User对象作为成员变量

package domain;

import java.io.Serializable;

/**
 * 数据库的account表对应的实体类
 */
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //从表实体应该包含一个主表实体的对象引用
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
}

<2>IAccountDao中添加findAll()方法

package dao;

import domain.Account;
import domain.AccountUser;

import java.util.List;

public interface IAccountDao {

    /**
     * 查询所有查询所有账户,及其用户名和地址信息
     * @return
     */
    List findAll();

  
}

<3>映射关系配置

(1)IAccountDao.xml配置

ResultMap标签基本作用:建立SQL查询结果字段与实体属性的映射关系信息

标签属性id和type的含义:

  id:该resultMap的标志
  type:返回值的类名

子标签含义:

  id:用于设置主键字段与领域模型属性的映射关系,此处主键为ID,对应id。
  result:用于设置普通字段与领域模型属性的映射关系
  association 为关联关系,是实现一对一的关键
    1. property 为javabean中容器对应字段名     
    2. javaType 指定关联的类型,当使用select属性时,无需指定关联的类型
    3. select 使用另一个select查询封装的结果
    4. column 为数据库中的列名,与select配合使用

 

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="dao.IAccountDao">

    <resultMap id="accountUserMap" type="domain.Account">
        <id property="id" column="aid">id>
        <result property="uid" column="uid">result>
        <result property="money" column="money">result>
        
        <association property="user" column="uid" javaType="domain.User">
            <id property="id" column="id">id>
            <result property="username" column="username">result>
            <result property="birthday" column="birthday">result>
            <result property="sex" column="sex">result>
            <result property="address" column="address">result>
        association>
    resultMap>
    
    
    
    <select id="findAll" resultMap="accountUserMap">
        select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
    select>


mapper>

注解配置:IAccountDao.java文件中进行如下配置

 /**
     * 查询所有查询所有账户,及其用户名和地址信息
     * 注解中的第四个result的column为uid(外键),连接到user表,select调用dao.IUserDao.findById()方法
     * @return
     */
    @Select("select * from account")
    @Results(id="accountMap",value = {
            @Result(id=true,column = "id",property = "id"),
            @Result(column = "uid",property = "uid"),
            @Result(column = "money",property = "money"),
            @Result(column = "uid",property = "user",one=@One(select = "dao.IUserDao.findById",fetchType = FetchType.EAGER))
    })
    List findAll();

<4>测试代码

package test;

import dao.IAccountDao;
import dao.IUserDao;
import domain.Account;
import domain.AccountUser;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

public class MybatisTest01 {

    private InputStream in;
    private SqlSession sqlSession;
    private IAccountDao accountDao;

    /**
     * 初始化MyBatis
     * @throws Exception
     */
    public void initMyBatis() throws Exception{
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory
        SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //创建SqlSessionFactory的构建者builder
        SqlSessionFactory factory=builder.build(in);  //利用构建者builder创建SqlSessionFactory
        //3.使用工厂生产SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSessions对象创建Dao接口的代理对象
        accountDao = sqlSession.getMapper(IAccountDao.class);
    }

    /**
     * 释放资源
     * @throws Exception
     */
    public void destroy() throws Exception{
        sqlSession.commit();//提交事务
        sqlSession.close();
        in.close();
    }

    /**
     * 查询所有
     * @throws Exception
     */
    @Test
    public void testFindAll()throws Exception{
        initMyBatis();
        List accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println(account);
            System.out.println(account.getUser());
        }
        destroy();
    }

  
}

效果图:

07 Mybatis的多表查询1----1对多和多对1_第1张图片

 

(2)案例2

查询所有查询用户信息,及其拥有的账户信息(逻辑为:用户信息表user-----》账户表account)

<1>对数据库表user对应的实体类User.java进行改造,加入List作为成员变量

package domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * 数据库表对应的实体类
 */
public class User implements Serializable {
    //实体类的成员变量名称应该与数据库中的列名一致
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List accounts;

    public List getAccounts() {
        return accounts;
    }

    public void setAccounts(List accounts) {
        this.accounts = accounts;
    }



    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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

<2>IUserDao中添加findAll()方法

package dao;

import domain.User;

import java.util.List;

/**
 *
 */
public interface IUserDao {
    /**
     * 查询所有
     * @return
     */
    List findAll();

}

<3>IUserDao.xml

ResultMap标签基本作用:建立SQL查询结果字段与实体属性的映射关系信息

标签属性id和type的含义:

  id:该resultMap的标志
  type:返回值的类名

子标签含义:

  id:用于设置主键字段与领域模型属性的映射关系,此处主键为ID,对应id。
  result:用于设置普通字段与领域模型属性的映射关系
  association 为关联关系,是实现一对一的关键 
    1. property 为javabean中容器对应字段名     
    2. javaType 指定关联的类型,当使用select属性时,无需指定关联的类型
    3. select 使用另一个select查询封装的结果
    4. column 为数据库中的列名

  collection 为关联关系,是实现一对多的关键
    1. property 为javabean中容器对应字段名
    2. ofType 指定集合中元素的对象类型
    3. select 使用另一个查询封装的结果
    4. column 为数据库中的列名,与select配合使用

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="dao.IUserDao">

    <resultMap id="userAccountMap" type="domain.User">
        <id property="id" column="id">id>
        <result property="username" column="username">result>
        <result property="birthday" column="birthday">result>
        <result property="sex" column="sex">result>
        <result property="address" column="address">result>
        
        <collection property="accounts" ofType="domain.Account">
            <id property="id" column="aid">id>
            <result property="uid" column="uid">result>
            <result property="money" column="money">result>
        collection>
    resultMap>
    
    <select id="findAll" resultMap="userAccountMap">
        select * from user u left outer join account a on u.id = a.uid
    select>
    
mapper>

注解配置:IUserDao.java文件中进行如下配置

/**
     * 查询所有
     * @return
     */
    @Select("select * from user")
    @Results(id="userMap",value = {
            @Result(id=true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "address",property = "address"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "id",property ="accounts",many =@Many(select = "dao.IAccountDao.findAccountById",fetchType = FetchType.EAGER))
    })
    List findAll();

<4>测试代码

package test;

import dao.IAccountDao;
import dao.IUserDao;
import domain.Account;
import domain.AccountUser;
import domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

public class MybatisTest02_User {

    private InputStream in;
    private SqlSession sqlSession;
    private IUserDao userDao;

    /**
     * 初始化MyBatis
     * @throws Exception
     */
    public void initMyBatis() throws Exception{
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory
        SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //创建SqlSessionFactory的构建者builder
        SqlSessionFactory factory=builder.build(in);  //利用构建者builder创建SqlSessionFactory
        //3.使用工厂生产SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSessions对象创建Dao接口的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    /**
     * 释放资源
     * @throws Exception
     */
    public void destroy() throws Exception{
        sqlSession.commit();//提交事务
        sqlSession.close();
        in.close();
    }

    /**
     * 查询所有
     * @throws Exception
     */
    @Test
    public void testFindAll()throws Exception{
        initMyBatis();
        List users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
            System.out.println(user.getAccounts());
        }
        destroy();
    }

}

效果图:

07 Mybatis的多表查询1----1对多和多对1_第2张图片

4.Mybatis中的缓存
(1)什么是缓存
  存在于内存中的临时数据。
(2)为什么使用缓存
  减少和数据库的交互次数,提高执行效率。
(3)什么样的数据能使用缓存,什么样的数据不能使用
  <1>适用于缓存:
    经常查询并且不经常改变的。
    数据的正确与否对最终结果影响不大的。
  <2>不适用于缓存:
    经常改变的数据
    数据的正确与否对最终结果影响很大的。
    例如:商品的库存,银行的汇率,股市的牌价。
5.Mybatis中的一级缓存和二级缓存
(1)一级缓存:
  它指的是Mybatis中SqlSession对象的缓存。
  当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
  该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
  查询是否有,有的话直接拿出来用。
  当SqlSession对象消失时,mybatis的一级缓存也就消失了。

(2)二级缓存:
  它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
  二级缓存的使用步骤:
    第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
    第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
    第三步:让当前的操作支持二级缓存(在select标签中配置)

转载于:https://www.cnblogs.com/luckyplj/p/11307874.html

你可能感兴趣的:(07 Mybatis的多表查询1----1对多和多对1)