首頁 > 軟體

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

2022-03-03 16:00:43

前言

表之間的關係有幾種:一對多、多對一、 一對一、多對多
在多對一關係中,把多的部分拆成一個一個物件其實就是一對一關係,如賬戶和使用者是多對一關係,但每個賬戶只對應一個使用者。所以在mybatis中,多對一的關係可以看成一對一的關係。
這裡我把一對多和多對一的xml設定方式總結了一下,同時還有載入方式。
一對多,多對多:通常情況下我們都是採用延遲載入。
多對一,一對一:通常情況下我們都是採用立即載入。
至於註解方式和多對多查詢的xml和註解方式我會另外寫部落格。

資料庫表及關係

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

一對多查詢

首先我們要在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多表查詢內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com