【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());
        }
    }
}

 

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