07 Mybatis的多表查詢1----1對多和多對1---@Results注解用法總結


1.表與表之間的關系及其舉例

表之間的關系有4種:一對多、多對一、一對一、多對多。
舉例:
  (1)用戶和訂單就是一對多

    一個用戶可以下多個訂單
  (2)訂單和用戶就是多對一
    多個訂單屬於同一個用戶

  (3)人和身份證號就是一對一
    一個人只能有一個身份證號
    一個身份證號只能屬於一個人

  (4)老師和學生之間就是多對多
    一個學生可以被多個老師教過
    一個老師可以交多個學生

2.mybatis中的多表查詢
示例:用戶和賬戶
  一個用戶可以有多個賬戶
  一個賬戶只能屬於一個用戶(多個賬戶也可以屬於同一個用戶)
步驟:
  1、建立兩張表:用戶表,賬戶表
    讓用戶表和賬戶表之間具備一對多的關系:需要使用外鍵在賬戶表中添加
  2、建立兩個實體類:用戶實體類和賬戶實體類
    讓用戶和賬戶的實體類能體現出來一對多的關系
  3、建立兩個配置文件
    用戶的配置文件
    賬戶的配置文件
  4、實現配置:
    當我們查詢用戶時,可以同時得到用戶下所包含的賬戶信息
    當我們查詢賬戶時,可以同時得到賬戶的所屬用戶信息

3.@Results注解用法總結:

MyBatis中使用@Results注解來映射查詢結果集到實體類屬性
(1)@Results的基本用法。當數據庫字段名與實體類對應的屬性名不一致時,可以使用@Results映射來將其對應起來。column為數據庫字段名,porperty為實體類屬性名,jdbcType為數據庫字段數據類型,id為是否為主鍵。

@Select({"select id, name, class_id from my_student"})
@Results({
    @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
    @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
    @Result(column="class_id", property="classId", jdbcType=JdbcType.INTEGER)
})
List<Student> selectAll();

如上所示的數據庫字段名class_id與實體類屬性名classId,就通過這種方式建立了映射關系。

(2)@ResultMap的用法。當這段@Results代碼需要在多個方法用到時,為了提高代碼復用性,我們可以為這個@Results注解設置id,然后使用@ResultMap注解來復用這段代碼。

@Select({"select id, name, class_id from my_student"})
@Results(id="studentMap", value={
    @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
    @Result(column="class_id", property="classId", jdbcType=JdbcType.INTEGER)
})
List<Student> selectAll();
 
@Select({"select id, name, class_id from my_student where id = #{id}"})
@ResultMap(value="studentMap")
Student selectById(integer id);

(3)@One的用法。當我們需要通過查詢到的一個字段值作為參數,去執行另外一個方法來查詢關聯的內容,而且兩者是一對一關系時,可以使用@One注解來便捷的實現。比如當我們需要查詢學生信息以及其所屬班級信息時,需要以查詢到的class_id為參數,來執行ClassesMapper中的selectById方法,從而獲得學生所屬的班級信息。可以使用如下代碼。

@Select({"select id, name, class_id from my_student"})
@Results(id="studentMap", value={
    @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
    @Result(column="class_id", property="myClass", javaType=MyClass.class,
        one=@One(select="com.example.demo.mapper.MyClassMapper.selectById"))
})
List<Student> selectAllAndClassMsg();

(4)@Many的用法。與@One類似,只不過如果使用@One查詢到的結果是多行,會拋出TooManyResultException異常,這種時候應該使用的是@Many注解,實現一對多的查詢。比如在需要查詢學生信息和每次考試的成績信息時。

@Select({"select id, name, class_id from my_student"})
@Results(id="studentMap", value={
    @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
    @Result(column="class_id", property="classId", jdbcType=JdbcType.INTEGER),
    @Result(column="id", property="gradeList", javaType=List.class,
        many=@Many(select="com.example.demo.mapper.GradeMapper.selectByStudentId"))
})
List<Student> selectAllAndGrade();

參考文獻:https://blog.csdn.net/cherlshall/article/details/80950150

4.操作案例

(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<Account> 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>
        <!--配置所外鍵所關聯表user的內容-->
        <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>
    
    <!-- 查詢所有查詢所有賬戶,及其用戶名和地址信息:方法1(更通用) -->
    <!--account a 給account表起一個別名-->
    <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<Account> 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<Account> accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println(account);
            System.out.println(account.getUser());
        }
        destroy();
    }

  
}

效果圖:

 

(2)案例2

查詢所有查詢用戶信息,及其擁有的賬戶信息(邏輯為:用戶信息表user-----》賬戶表account)

<1>對數據庫表user對應的實體類User.java進行改造,加入List<Account>作為成員變量

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<Account> accounts;

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> 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<User> 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>
        <!--配置user對象中accounts集合的映射-->
        <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<User> 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<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
            System.out.println(user.getAccounts());
        }
        destroy();
    }

}

效果圖:

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標簽中配置)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM