【MyBatis】多表查詢

MyBatis的多表查詢

表之間的關係:一對多,多對一,一對一,多對多。

一對多:一個班級對應多個學生

多對一:多個學生對應一個班級

一對一:一個人對應一個身份證號碼

多對多:一個訂單可以有多個商品,一個商品也可以對應多個訂單。

一對一

新建一個賬戶信息表:

其中ID是主鍵,UID對應於user表的id

需求:查詢所有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;
    }

    public Account(Integer id, Integer uid, Double money) {
        this.id = id;
        this.uid = uid;
        this.money = money;
    }

    public Account() {
    }

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

由於只使用Account類只能包含賬戶信息,無法包含用戶用戶信息,因此新建一個類AccountUser繼承與Account類:

public class AccountUser extends Account {
    private String username;
    private String address;

    @Override
    public String toString() {
        return super.toString()+"   AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

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

對應的xml文件:

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

    <!--查詢所有-->
    <select id="findAll" resultType="com.lwl.domain.Account">
        select * from account;
    </select>

    <!--查詢所有賬戶,包含用戶名和地址-->
    <select id="findAllAccount" resultType="com.lwl.domain.AccountUser">
        select a.*,u.username,u.address from account a, user u where u.id=a.uid;
    </select>

</mapper>

創建測試類進行測試:

public class AccountTest {
    private InputStream is;
    private SqlSession sqlSession;
    private IAccountDao accountDao;

    //初始化進行封裝
    @Before //用於在測試方法執行之前執行
    public void init() throws Exception {
        //1.讀取配置文件,形成字節輸入流
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3.獲取SqlSession對象
        sqlSession = factory.openSession();
        //4.獲取dao的代理對象
        accountDao = sqlSession.getMapper(IAccountDao.class);
    }
    //close進行封裝
    @After //用於在測試方法執行之後執行
    public void distory() throws Exception {
        //提交事務
        sqlSession.commit();
        //6.關閉資源
        sqlSession.close();
        is.close();
    }

    //查詢所有賬戶
    @Test
    public void testFindAll(){
        List<Account> accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println(account);
        }
    }

    //查詢所有賬戶,幷包含用戶名和地址
    @Test
    public void testFindAllAccount(){
        List<AccountUser> accountUsers = accountDao.findAllAccount();
        for (AccountUser accountUser : accountUsers) {
            System.out.println(accountUser);
        }
    }

}

查詢結果:

 方式二:

使用resultMap,定義專門的resultMap用於映射一對一查詢結果。 通過面向對象的關係可以得知,我們可以在Account類中加入一個User類的對象來代表這個賬戶是哪個用戶的。

resultMap關鍵字

resultType

resultType可以把查詢結果封裝到pojo類型中,但必須pojo類的屬性名和查詢到的數據庫表的字段名一致。
如果sql查詢到的字段與pojo的屬性名不一致,則需要使用resultMap將字段名和屬性名對應起來,進行手動配置封裝,將結果映射到pojo中。

<!-- resultMap最終還是要將結果映射到pojo上,type就是指定映射到哪一個pojo -->
    <!-- id:設置ResultMap的id -->
    <resultMap type="User" id="UserResultMap">
        <!-- property:pojo中的屬性名 -->
        <!-- column:對應在數據庫中的列名 -->
        <id property="id" column="id" />

        <!-- 定義普通屬性 -->
        <result property="name" column="username" />
        <result property="usersex" column="sex" />
        <result property="old" column="age" />
        <result property="address" column="address" />
    </resultMap>

resultMap可以實現將查詢結果映射爲複雜類型的pojo,比如在查詢結果映射對象中包括pojo和list實現一對一查詢和一對多查詢。例如:

    <!--定義封裝account和user的resultMap-->
    <resultMap id="accountUserMap" type="com.lwl.domain.Account">
        <!--property爲當前類的屬性,即count類,column爲主表數據庫的列名,主鍵用id標籤-->
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--user屬性屬於另一個類的實例,需要進行映射-->
        <!--association :一對一的關係映射,對user實例的內容進行封裝-->
        <!--property:是accout類中需要映射的user屬性,column是其在user屬性在count數據庫中對應的表名,javaType是其user對應的類-->
        <association property="user" column="uid" javaType="com.lwl.domain.User">
            <!--property爲當前類的屬性,column爲主表數據庫的列名,主鍵用id標籤-->
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
            <result property="sex" column="sex"></result>
        </association>
    </resultMap>

參考鏈接:https://blog.csdn.net/qq_42780864/article/details/81429114

修改Account類

從表實體應該包含一個主表的對象的實例

 重新定義AccountDao.xml文件

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

    <!--定義封裝account和user的resultMap-->
    <resultMap id="accountUserMap" type="com.lwl.domain.Account">
        <!--property爲當前類的屬性,column爲主表數據庫的列名,主鍵用id標籤-->
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--association :一對一的關係映射,配置user的內容,-->
        <!--property:是accout類中user屬性,column是其在數據庫中對應的表名,javaType是其對應的類-->
        <association property="user" column="uid" javaType="com.lwl.domain.User">
            <!--property爲當前類的屬性,column爲主表數據庫的列名,主鍵用id標籤-->
            <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="age" column="age"></result>
            <result property="email" column="email"></result>
            <result property="qq" column="qq"></result>
        </association>
    </resultMap>

    <!--查詢所有-->
    <select id="findAll" resultMap="accountUserMap">
        select a.*,u.* from account a, user u where u.id=a.uid;
    </select>

    <!--查詢所有賬戶,包含用戶名和地址-->
    <select id="findAllAccount" resultType="com.lwl.domain.AccountUser">
        select a.*,u.username,u.address from account a, user u where u.id=a.uid;
    </select>

</mapper>

在AccountTest類中加入測試方法

    //查詢所有賬戶及用戶信息
    @Test
    public void testFindAll(){
        List<Account> accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }

一對多

修改count表的數據,使部分的user具有多個賬戶。

修改User對應,增加賬戶的集合屬性,以及對應的get和set方法

    private List<Account> accounts;

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

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

 創建IUserDao.xml

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

    <!--定義User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="sex" column="sex"></result>
        <result property="age" column="age"></result>
        <result property="email" column="email"></result>
        <result property="address" column="address"></result>
        <result property="qq" column="qq"></result>

        <!--配置user對象中accounts集合的映射-->
        <collection property="accounts" ofType="com.lwl.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 a.uid=u.id;
    </select>
</mapper>

創建測試類進行查詢:


public class UserTest {
    private InputStream is;
    private SqlSession sqlSession;
    private IUserDao userDao;

    //初始化進行封裝
    @Before //用於在測試方法執行之前執行
    public void init() throws IOException {
        //1.讀取配置文件,形成字節輸入流
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3.獲取SqlSession對象
        sqlSession = factory.openSession();
        //4.獲取dao的代理對象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    //close進行封裝
    @After //用於在測試方法執行之後執行
    public void distory() throws IOException {
        //提交事務
        sqlSession.commit();
        //6.關閉資源
        sqlSession.close();
        is.close();
    }

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

多對多

        示例:用戶和角色
            一個用戶可以有多個角色
            一個角色可以賦予多個用戶
        步驟:
            1、建立兩張表:用戶表,角色表
                讓用戶表和角色表具有多對多的關係。需要使用中間表,中間表中包含各自的主鍵,在中間表中是外鍵。
            2、建立兩個實體類:用戶實體類和角色實體類
                讓用戶和角色的實體類能體現出來多對多的關係
                各自包含對方一個集合引用
            3、建立兩個配置文件
                用戶的配置文件
                角色的配置文件
            4、實現配置:
                當我們查詢用戶時,可以同時得到用戶所包含的角色信息
                當我們查詢角色時,可以同時得到角色的所賦予的用戶信息

創建數據庫:

上面一個是role表。另一個是中間表,指定兩表之間的關聯。

創建角色Role類並提供set和get以及toString方法:

public class Role implements Serializable {
    private Integer roleId;
    private String roleName;
    private String roleDesc;
    //set和get略
}

創建相應Dao接口:

public interface IRoleDao {
    List<Role> findAll();
}

映射的xml文件:

注意類中的屬性名和數據庫中的列名不一樣

    <resultMap id="roleMap" type="role">
        <id property="roleId" column="id"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
    </resultMap>
    
    <!--查詢所有-->
    <select id="findAll" resultMap="roleMap">
        select * from role;
    </select>

進行查詢測試:

public class RoleTest {
    private InputStream is;
    private SqlSession sqlSession;
    private IRoleDao roleDao;

    //初始化進行封裝
    @Before //用於在測試方法執行之前執行
    public void init() throws IOException {
        //1.讀取配置文件,形成字節輸入流
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3.獲取SqlSession對象
        sqlSession = factory.openSession();
        //4.獲取dao的代理對象
        roleDao = sqlSession.getMapper(IRoleDao.class);
    }

    //close進行封裝
    @After //用於在測試方法執行之後執行
    public void distory() throws IOException {
        //提交事務
        sqlSession.commit();
        //6.關閉資源
        sqlSession.close();
        is.close();
    }

    //測試查詢所有
    @Test
    public void testFindAll(){
        List<Role> roles = roleDao.findAll();
        for (Role role : roles) {
            System.out.println(role);
        }
    }
}

接下來實現:
                當我們查詢角色時,可以同時得到角色的所賦予的用戶信息

在Role添加User的一個實例:

    private List<User> users;

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

在IRoleDao.xml中進行修改:

<?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="com.lwl.dao.IRoleDao">
    
    <resultMap id="roleMap" type="role">
        <!--寫成rid是因爲在SQL語句中對id起了別名爲rid-->
        <id property="roleId" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <collection property="users" ofType="user">
            <id column="id" property="id"></id>
            <result column="username" property="username"></result>
            <result column="address" property="address"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
        </collection>
    </resultMap>
    
    <!--查詢所有-->
    <select id="findAll" resultMap="roleMap">
        select u.*,r.id as rid,r.role_name,r.role_desc from role r
        left outer join user_role ur  on r.id = ur.rid
        left outer join user u on u.id = ur.uid

    </select>
    
</mapper>
    

測試:

    //測試查詢所有
    @Test
    public void testFindAll(){
        List<Role> roles = roleDao.findAll();
        for (Role role : roles) {
            System.out.println(role);
            System.out.println(role.getUsers());
        }
    }

接下來實現:
                當我們查詢角色時,可以同時得到角色的所賦予的用戶信息

修改SQL語句:

        select u.*,r.id as rid,r.role_name,r.role_desc from user u
        left outer join user_role ur  on u.id = ur.uid
        left outer join role r on r.id = ur.rid

在User表中添加Role的實例:

    private List<Role> roles;

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

配置xml

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

    <resultMap id="userMap" type="user">
        <!--寫成rid是因爲在SQL語句中對id起了別名爲rid-->
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="address" property="address"></result>
        <result column="sex" property="sex"></result>
        <result column="birthday" property="birthday"></result>
        <collection property="roles" ofType="role">
            <id property="roleId" column="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
    </resultMap>

    <!--查詢所有-->
    <select id="findAll" resultMap="userMap">
        select u.*,r.id as rid,r.role_name,r.role_desc from user u
        left outer join user_role ur  on u.id = ur.uid
        left outer join role r on r.id = ur.rid
    </select>

</mapper>

進行測試:


/**
 * @author liwenlong
 * @data 2020/5/4
 */
public class UserTest {
    private InputStream is;
    private SqlSession sqlSession;
    private IUserDao userDao;

    //初始化進行封裝
    @Before //用於在測試方法執行之前執行
    public void init() throws IOException {
        //1.讀取配置文件,形成字節輸入流
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3.獲取SqlSession對象
        sqlSession = factory.openSession();
        //4.獲取dao的代理對象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    //close進行封裝
    @After //用於在測試方法執行之後執行
    public void distory() throws IOException {
        //提交事務
        sqlSession.commit();
        //6.關閉資源
        sqlSession.close();
        is.close();
    }

    //測試查詢所有
    @Test
    public void testFindAll(){
        //5.執行查詢所有方法
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
            System.out.println(user.getRoles());
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章