mybatis多表查詢的實現(xml方式)

前言

表之間的關系有幾種:一對多、多對一、 一對一、多對多
在多對一關系中,把多的部分拆成一個一個對象其實就是一對一關系,如賬戶和用戶是多對一關系,但每個賬戶隻對應一個用戶。所以在mybatis中,多對一的關系可以看成一對一的關系。
這裡我把一對多和多對一的xml配置方式總結瞭一下,同時還有加載方式。
一對多,多對多:通常情況下我們都是采用延遲加載。
多對一,一對一:通常情況下我們都是采用立即加載。
至於註解方式和多對多查詢的xml和註解方式我會另外寫博客。

數據庫表及關系

我們以用戶和賬戶為例,用戶可以有多個賬戶,賬戶隻能對應一個用戶。所以用戶對賬戶是一對多關系,賬戶對用戶是多對一關系。表如下圖所示,用戶表user,賬戶表account,賬戶表UID對應用戶表id。

用戶表user

賬戶表account

一對多查詢

首先我們要在User實體類中添加List accounts的集合成員變量,表示一對多映射關系,主表實體含有從表實體的集合引用。

public class User implements Serializable{
    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;

    //一對多映射關系,主表實體含有從表實體的集合引用
    private List<Account> accounts;

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

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

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

    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 getAddress() {
        return address;
    }

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

    public String getSex() {
        return sex;
    }

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

    public Date getBirthday() {
        return birthday;
    }

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

同時在User Dao接口中提供查詢所有方法findAll,在Account Dao接口中提供根據id查詢user的方法findById,以便延時加載時調用。
這裡說明因為用戶可能對應許多賬戶,當我們查詢用戶時可能並不需要賬戶信息,而且如果我們每次查詢用戶時都立即查詢用戶的賬戶信息,並且賬戶信息有很多,勢必對內存有很大的開銷。所以當我們需要賬戶信息時再調用findById方法去查詢用戶對應的賬戶信息。

public interface IUserDao {
    /**
     * 查詢所有操作,並攜帶賬戶信息
     * @return
     */
    List<User> findAll();

    /**
     * 根據id查詢一個用戶
     * @param uid
     */
    User findById(Integer uid);


}
public interface IAccountDao {
    /**
     * 查詢所有賬戶
     * @return
     */
    List<Account> findAll();

    /**
     * 根據用戶id查詢賬戶
     * @param uid
     * @return
     */
    List<Account> findByUid(Integer uid);

}

然後配置userDao.xml,說明會在代碼中給出。

<mapper namespace="com.cc.dao.IUserDao">
    <!--定義resultMap-->
    <!--因為在主配置文件中配置瞭domain包下的所有實體類別名,所以這裡封裝類型隻需要寫實體類名即可,不分大小寫-->
    <resultMap id="userWithAccount" type="user">
        <!--封裝user對象-->
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!--配置user隊形中account集合的映射-->
        <!--定義一對多的關系映射,實現對account的封裝,用collection標簽
        ofType屬性指定內容:要封裝的實體對象類型
        select屬性指定內容:查詢用戶的唯一標識
        column屬性指定內容:用戶根據id查詢是所需要的參數
        -->
        <collection property="accounts" ofType="account" column="id" select="com.cc.dao.IAccountDao.findByUid"></collection>
    </resultMap>
    <!--查詢所有-->
    <select id="findAll" resultMap="userWithAccount">
        select * from user
    </select>
    <!--根據id查詢一個用戶-->
    <select id="findById" parameterType="java.lang.Integer" resultType="user">
        select * from user where id=#{uid};
    </select>
</mapper>

當然我們還要在主配置文件中開啟延時加載,默認情況下是立即加載。
lazyLoadingEnabled:是否啟用延遲加載,mybatis默認為false,不啟用延遲加載。lazyLoadingEnabled屬性控制全局是否使用延遲加載,特殊關聯關系也可以通過嵌套查詢中fetchType屬性單獨配置(fetchType屬性值lazy或者eager)。
也就是說我們可以不用在主配置文件中配置而在userDao.xml中配置,這裡我們采用全局配置。

<!--配置參數-->
    <settings>
        <!--開啟Mybatis支持延時加載-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"></setting>
    </settings>
    <!--配置domain包下所有實體類別名-->
    <typeAliases>
        <!--<typeAlias type="com.cc.domain.User" alias="user"></typeAlias>-->
        <package name="com.cc.domain"></package>
    </typeAliases>

然後我們就可以測試瞭

public class UserTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private IUserDao userDao;
    @Before//在測試方法執行之前執行
    public void init() throws IOException {
        //1.讀取配置文件,生成字節輸入流
         in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.生成SqlSessionFactory
         factory = new SqlSessionFactoryBuilder().build(in);
        //3.獲取SqlSession
         sqlSession = factory.openSession();
        //4.獲取dao的代理對象
         userDao = sqlSession.getMapper(IUserDao.class);
    }
    @After//在測試方法執行之後執行
    public void destory() throws IOException {
        //提交事務
        sqlSession.commit();
        //關閉資源
        sqlSession.close();
        in.close();
    }

    /**
     * 測試查詢所有賬戶
     */
    @Test
    public void TestFindAll() {
        //5.執行查詢所有方法
        List<User> userList = userDao.findAll();
       for (User user : userList) {
           System.out.println(user);
            System.out.println(user.getAccounts());
        }

    }

}

先把遍歷輸出部分代碼註釋掉,測試可以看出我們隻查詢瞭用戶信息。

在這裡插入圖片描述

然後去掉註釋,發現當我們需要輸出用戶賬戶時,他就會去查詢用戶的賬戶信息。

在這裡插入圖片描述

多對一及一對一查詢

步驟其實和一對多差不多。
首先我們在account實體類中加入user成員變量表示一對一映射。

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 +
                '}';
    }
}

Dao接口中需要的的方法在上面總結一對多查詢時的圖中已經給出。
然後配置accountDao.xml,這裡是立即查詢,在我們已經配置全局延時加載的情況下,我們需要配置fetchType=“eager”。

<mapper namespace="com.cc.dao.IAccountDao">
    <!--開啟account支持二級緩存-->
    <cache/>
    <!--定義封裝account和user的resultMap-->
    <resultMap id="accountAndUser" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--定義一對一的關系映射,實現對user的封裝
        select屬性指定內容:查詢用戶的唯一標識
        column屬性指定內容:用戶根據id查詢是所需要的參數
        fetchType屬性指定內容:lazy延時加載,eager立即加載。
        -->
        <association property="user" column="uid" javaType="user" select="com.cc.dao.IUserDao.findById" fetchType="eager"></association>
    </resultMap>
    <!--查詢所有-->
    <select id="findAll" resultMap="accountAndUser">
        SELECT * from account
    </select>
    <!--根據用戶id查詢-->
    <select id="findByUid" parameterType="java.lang.Integer" resultType="account" useCache="true">
        select * from account where uid = #{uid}
    </select>
</mapper>

然後我們就可以測試。可以看出當查詢賬戶時就立即查詢瞭對應的用戶信息。

在這裡插入圖片描述

總結

第一嘗試博客,肯定有很多欠缺的地方,希望大傢看到能評論指出。我自己學mybatis時間也不是很長,這裡隻給出瞭簡單的案例。如果什麼理解不到位的地方也請大傢諒解並指出。以後我會更多的寫博客,希望能夠給一起處在學習階段的人一些啟發。

到此這篇關於mybatis多表查詢的實現(xml方式)的文章就介紹到這瞭,更多相關mybatis多表查詢內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: