mybatis多表查询的实现(xml方式)

目录
  • 前言
  • 数据库表及关系
  • 一对多查询
  • 多对一及一对一查询
  • 总结

前言

表之间的关系有几种:一对多、多对一、 一对一、多对多
在多对一关系中,把多的部分拆成一个一个对象其实就是一对一关系,如账户和用户是多对一关系,但每个账户只对应一个用户。所以在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多表查询内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MyBatis XML方式的基本用法之多表查询功能的示例代码

    1. 多表查询 在之前,我们示例的2个查询都是单表查询,但实际的业务场景肯定是需要多表查询的,比如现在有个需求: 查询某个用户拥有的所有角色.这个需求要涉及到sys_user,sys_user_role,sys_role三张表,如何实现呢? 首先,在SysUserMapper接口中定义如下方法. /** * 根据用户id获取角色信息 * * @param userId * @return */ List<SysRole> selectRolesByUserId(Long userId); 然后

  • Java工程mybatis实现多表查询过程详解

    1.先做一些准备工作 我们首先在创建一个 java 工程,还需要创建两张表,它们分别是用户表 user,和帖子表 post,一个户用户可以有多个帖子. user表的结构和数据: -- ---------------------------- -- Table structure for `user` -- ---------------------------- CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT

  • Mybatis基于注解实现多表查询功能

    对应的四种数据库表关系中存在四种关系:一对多,多对应,一对一,多对多.在前文中已经实现了xml配置方式实现表关系的查询,本文记录一下Mybatis怎么通过注解实现多表的查询,算是一个知识的补充. 同样的先介绍一下Demo的情况:存在两个实体类用户类和账户类,用户类可能存在多个账户,即一对多的表关系.每个账户只能属于一个用户,即一对一或者多对一关系.我们最后实现两个方法,第一个实现查询所有用户信息并同时查询出每个用户的账户信息,第二个实现查询所有的账户信息并且同时查询出其所属的用户信息. 1.项目

  • springboot整合mybatis实现多表查询的实战记录

    目录 什么是mybatis 1.一对一查询(例一个用户一个账户) 1.1.实体类 1.2.数据库表 1.3.持久层接口 2.一对多查询(例一个用户对应多个账户) 2.1.实体类 2.2.数据库表 2.3.持久层接口 3.总结 4.多对多的查询(例一个用户多个角色) 4.1.实体类 4.2.数据库表 4.3.持久层接口 5.多对一(一个用户对应多个老师) 5.1 实体类 5.2.数据库表 5.3.持久层接口 总结 什么是mybatis (1)Mybatis 是一个半 ORM(对象关系映射)框架,它

  • MybatisPlus自定义Sql实现多表查询的示例

    前言 前段时间看同事的代码,发现他用Layui+MybatisPlus做分页查询做得很规整,认真看了下代码发现这种方式不仅适用于与Layui做分页查询,在任何时候需要多表联查的时候都可以用到.  以下以Layui分页查询作为参考,在实际应用中可以灵活使用. 分页查询VO对象 @Data @AllArgsConstructor @NoArgsConstructor public class LayuiData { private Integer code=0; private Long count

  • 结合mybatis-plus实现简单不需要写sql的多表查询

    项目地址: GITHUB (本地下载) java mybatis 多表查询 简介 实现简单的实体类操作多表,  首先你的项目是使用了mybatis-plus 才可以使用 设计说明 如何关联表? 找第一张表注解为 TableId (mybatis-plus 注解)的属性名, 到每二张表找同样的属性名, 如果没找到,反过来找,如果还没找到,挨个属性找.以此类推,实现关联的前提条件是 主从表的关联例名必须一样 // user 表 @TableId private Integer userId // a

  • Java MyBatis 多表查询详解

    目录 多表查询: 一对一: 一对多: 多对多: 总结 多表查询: 学生表.班级表.课程表.班级课程表 一对一: 一个学生只属于一个班级. 查询: id  name  age  gender   banjiName SELECT s.id,s.`name`,s.age,s.gender,b.id AS banjiId,b.name AS banjiName FROM student AS s INNER JOIN banji AS b ON s.banji_id=b.id; MyBatis中使用a

  • MyBatis如何实现多表查询(多对一、一对多)

    MyBatis实现多表查询 一.多对一查询 数据库的准备 创建两张表,一张老师表,一张学生表 将老师主键id关联学生外键tid 创建sql的语句 create table teacher( id int primary key, teacher_name varchar(30) not null ) insert into teacher(id,teacher_name) values (1,'毛老师') create table student( id int primary key, stu

  • mybatis多表查询的实现(xml方式)

    目录 前言 数据库表及关系 一对多查询 多对一及一对一查询 总结 前言 表之间的关系有几种:一对多.多对一. 一对一.多对多在多对一关系中,把多的部分拆成一个一个对象其实就是一对一关系,如账户和用户是多对一关系,但每个账户只对应一个用户.所以在mybatis中,多对一的关系可以看成一对一的关系.这里我把一对多和多对一的xml配置方式总结了一下,同时还有加载方式.一对多,多对多:通常情况下我们都是采用延迟加载.多对一,一对一:通常情况下我们都是采用立即加载.至于注解方式和多对多查询的xml和注解方

  • Mybatis多表查询与动态SQL特性详解

    目录 1.较复杂的查询操作 1.1 参数占位符 #{} 和 ${} 1.2SQL注入 1.3like查询 1.4resultType与resultMap 1.4多表查询 1.4.1一对一表映射 1.4.2一对多表映射 2.动态SQL 2.1if标签 2.2trim标签 2.3where标签 2.4set标签 2.5foreach标签 总结 1.较复杂的查询操作 1.1 参数占位符 #{} 和 ${} #{}:预处理符,如将id=#{2}替换为id=?,然后使用2替换?. ${}:替换符,如将id

  • MyBatis实现模糊查询的几种方式

    在学习MyBatis过程中想实现模糊查询,可惜失败了.后来上百度上查了一下,算是解决了.记录一下MyBatis实现模糊查询的几种方式. 数据库表名为test_student,初始化了几条记录,如图: 起初我在MyBatis的mapper文件中是这样写的: <select id="searchStudents" resultType="com.example.entity.StudentEntity" parameterType="com.exampl

  • Spring Data Jpa多表查询返回自定义实体方式

    目录 SpringDataJpa多表查询返回自定义实体 Repository 好下面到单元测试 自定义实体 SpringDataJpa多表查询返回自定义VO的问题 下面是我的代码 下面是我的dao层,重点 SpringDataJpa多表查询返回自定义实体 比如来看一下这样的一条SQL语句,这是一个三张表的多表查询,显然在JPA中用一个实体类是接受不了这些参数的 select  t1.id as chapterId , t1.name as chapterName , t2.id as unitI

  • Mybatis实现联表查询并且分页功能

    今天同学突然问我这个怎么搞. 然后自己搞了一下发现这个玩意有坑..就记录一下 0. 表结构 person表 cat表 一个person有多个cat 实体类就这么写 1. 实体类 Person实体类 @Data public class Person implements Serializable { private static final long serialVersionUID = -70682701290685641L; private Integer personid; private

  • Mybatis使用连表查询的操作代码

    某天,产品经理给了这么一个需求技术小哥,能不能帮用户添加一个搜索栏,查询包含某个关键字的所有类目.技术小哥稍微想了一下,目前跟类目相关的表有两个,一个是content_category类目表,一个是content_system内容系统表.而用户要查找的关键字是存在content_system表里面,这样一来需要连表查询一下.难度好像不大,也就爽快地答应了. 技术小哥再仔细分析了一下两个表的结构: CREATE TABLE `content_category` ( `category_id` in

随机推荐