MyBatis之三:多表联合查询

  在这篇文章里面主要讲解如何在mybatis里面使用一对一、一对多、多表联合查询(类似视图)操作的例子。

  注:阅读本文前请先大概看一下之前两篇文章。

  一、表结构

  班级表class,学生表student,班级学生关系表ClassStudent。

  这里一个学生只会在一个班级里面,也就是一对一的关系;一个班级有多个学生,也就是一对多的关系。

  结构如下:

CREATE TABLE [dbo].[Class](
    [class_id] [int] NOT NULL,
    [class_name] [varchar](50) NOT NULL,
 CONSTRAINT [PK_Class] PRIMARY KEY CLUSTERED
(
    [class_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[ClassStudent](
    [class_id] [int] NOT NULL,
    [student_id] [int] NOT NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[Student](
    [s_id] [int] NOT NULL,
    [s_name] [varchar](50) NOT NULL,
 CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED
(
    [s_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

    3张表的数据如下:

insert into Class values(1,‘三(1)班‘)
insert into Class values(2,‘三(2)班‘)
insert into Class values(3,‘三(3)班‘)
insert into Class values(4,‘三(4)班‘)

insert into Student values(1001,‘张三‘)
insert into Student values(1002,‘李四‘)
insert into Student values(1003,‘赵五‘)
insert into Student values(1004,‘王二麻子‘)

insert into ClassStudent values(1,1001)
insert into ClassStudent values(1,1003)
insert into ClassStudent values(4,1002)
insert into ClassStudent values(3,1004)

  

  二、在原项目下新建一个包com.mybatis.sqljoinrelation,在包里面新建一个sqlMapper.xml的映射文件,在项目的mybatis的配置文件conf.xml中对这个sqlMapper.xml进行注册,注册片段如下:

<!-- 注册映射文件 -->
    <mappers>
        <mapper resource="com/mybatis/sqljoinrelation/sqlMapper.xml" />
    </mappers>

  紧接着在原项目下再新建一个包com.mybatis.bean,在里面新建实体类

  学生:

package com.mybatis.bean;

/**
 * 学生(临时)
 */
public class StudentTemp {
    private int studentid;
    private String studentname;
    private Class tempClass;

    public Class getTempClass() {
        return tempClass;
    }
    public void setTempClass(Class tempClass) {
        this.tempClass = tempClass;
    }
    public int getStudentid() {
        return studentid;
    }
    public void setStudentid(int studentid) {
        this.studentid = studentid;
    }
    public String getStudentname() {
        return studentname;
    }
    public void setStudentname(String studentname) {
        this.studentname = studentname;
    }

    @Override
    public String toString() {
        return "StudentTemp [studentid=" + studentid + ", studentname="
                + studentname + ", tempClass=" + tempClass + "]";
    }

}

  班级:

package com.mybatis.bean;

/**
 * 班级
 */
public class Class {
    private int classid;
    private String classname;

    public int getClassid() {
        return classid;
    }
    public void setClassid(int classid) {
        this.classid = classid;
    }
    public String getClassname() {
        return classname;
    }
    public void setClassname(String classname) {
        this.classname = classname;
    }

    @Override
    public String toString() {
        return "Class [classid=" + classid + ", classname=" + classname + "]";
    }
}

  学生班级视图类:

package com.mybatis.bean;

public class studentclass {
    private int s_id;
    private String s_name;
    private int class_id;
    private String class_name;
    public int getS_id() {
        return s_id;
    }
    public void setS_id(int s_id) {
        this.s_id = s_id;
    }
    public String getS_name() {
        return s_name;
    }
    public void setS_name(String s_name) {
        this.s_name = s_name;
    }
    public int getClass_id() {
        return class_id;
    }
    public void setClass_id(int class_id) {
        this.class_id = class_id;
    }
    public String getClass_name() {
        return class_name;
    }
    public void setClass_name(String class_name) {
        this.class_name = class_name;
    }
    @Override
    public String toString() {
        return "studentclass [s_id=" + s_id + ", s_name=" + s_name
                + ", class_id=" + class_id + ", class_name=" + class_name + "]";
    }

}

  三、查询操作

  1、 一对一,查询学生编号等于1001且他所在班级信息

  2、一对多,查询班级编号等于1且包含所有学生信息

  3、类似视图查询学生编号等于1001且他所在班级信息

  sqlMapper.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.mybatis.sqljoinrelation.sqlMapper">

    <!-- 1、 获取某学生以及该学生所在班级的信息 -->
    <!-- 可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明,
        如果用"*"代替,则mybatis会自动匹配resultMap中提供的列名 -->
    <select id="getStudentAndClass" parameterType="int" resultMap="studentClassMap">
        select c.class_id,c.class_name,s.s_id,s.s_name
        from Class c left join ClassStudent cs
                on c.class_id = cs.class_id
            left join Student s
                on cs.student_id = s.s_id
        where s.s_id = #{id}
    </select>

    <!-- resultMap中的type表示返回什么类型的对象 -->
    <resultMap type="com.mybatis.bean.StudentTemp" id="studentClassMap">
        <!-- property 表示com.mybatis.bean.StudentTemp中的属性; column 表示表中的列名 -->
        <id property="studentid" column="s_id" />
        <result property="studentname" column="s_name" />

        <!-- association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称;
            javaType表示该属性是什么类型对象 -->
        <association property="tempClass" javaType="com.mybatis.bean.Class">
            <!-- property 表示com.mybatis.bean.Class中的属性; column 表示表中的列名 -->
            <id property="classid" column="class_id" />
            <result property="classname" column="class_name" />
        </association>
    </resultMap>

    <!-- 2、获取某学生以及该学生所在班级的信息,类似视图实现方式 -->
    <!-- resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样;
         resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射 -->
    <select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass">
        select c.class_id,c.class_name,s.s_id,s.s_name
        from Class c left join ClassStudent cs
                on c.class_id = cs.class_id
            left join Student s
                on cs.student_id = s.s_id
        where s.s_id = #{id}
    </select>

    <!-- 3、获取某班级以及班级里面所有学生的信息 -->
    <select id="getClassStudents" parameterType="int" resultMap="classStudentsMap">
        select *
        from Class c left join ClassStudent cs
                on c.class_id = cs.class_id
            left join Student s
                on cs.student_id = s.s_id
        where c.class_id = #{id}
    </select>
    <resultMap type="com.mybatis.bean.ClassTemp" id="classStudentsMap">
        <id property="classid" column="class_id"/>
        <result property="classname" column="class_name"/>

        <!-- property表示集合类型属性名称,ofType表示集合中的对象是什么类型 -->
        <collection property="students" ofType="com.mybatis.bean.Student">
            <id property="studentid" column="s_id"/>
        <result property="studentname" column="s_name"/>
        </collection>
    </resultMap>
</mapper>

  测试代码如下:

  一对一与类似视图查询的代码在一起,如下:

package com.mybatis.sqljoinrelation;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.mybatis.util.MybatisUtils;

/**
 * 一对一
 */
public class testonetoone {
    public static void main(String[] args) {
        SqlSessionFactory factory = MybatisUtils.getFactory();
        SqlSession session = null;
        try {
            session = factory.openSession(true);

            //1、StudentTemp
            String statement1 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClass";
            System.out.println(session.selectOne(statement1, 1001)); 

            //2、用model类型接收数据
            String statement2 = "com.mybatis.sqljoinrelation.sqlMapper.getStudentAndClassView";
            System.out.println(session.selectOne(statement2, 1001)); 

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            session.close();
        }
    }
}

  一对多测试代码如下:

package com.mybatis.sqljoinrelation;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.mybatis.util.MybatisUtils;

/**
 * 一对多
 */
public class testonetomany {
    public static void main(String[] args) {
        SqlSessionFactory factory = MybatisUtils.getFactory();
        SqlSession session = null;
        try {
            session = factory.openSession(true);

            //1、StudentTemp
            String statement = "com.mybatis.sqljoinrelation.sqlMapper.getClassStudents";
            System.out.println(session.selectOne(statement, 1)); 

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            session.close();
        }
    }
}

  四、sqlMapper.xml需要说明的问题

  1、一对一:<association property="tempClass" javaType="com.mybatis.bean.Class">

    association字面意思关联,这里只专门做一对一关联; property表示是com.mybatis.bean.StudentTemp中的属性名称; javaType表示该属性是什么类型对象

    2、类似视图查询: <select id="getStudentAndClassView" parameterType="int" resultType="com.mybatis.bean.studentclass">

    resultType 对应简单类型,也就是实体中的属性名称与数据库表字段名称一模一样;
    resultMap 对应复杂类型,属性名称与字段名称不一样可以通过resultMap中property,column进行映射,其中一对一与一对多都是用resultMap来映射

  3、一对多:<collection property="students" ofType="com.mybatis.bean.Student">

   collection字面意思是集合,这里专门做一对多关联 ,property表示集合类型属性名称,ofType表示集合中的对象是什么类型

  4、<select>select * from ...</student>与<select>select 字段1,字段2,字段3... from ...</student>

   可以显示指出c.class_id,c.class_name,s.s_id,s.s_name列明,如果用"*"代替,则mybatis会自动匹配resultMap或者resultType中提供的列名,

     如果某对象存在列映射的属性,但是在select 后面找不到这个列,则在返回结果中,该列多映射的值为null。

  至此,对于一对一、一对多、视图查询都能很好的解决,主要还是要重点关注第四点说明。

      

时间: 2025-01-18 23:03:19

MyBatis之三:多表联合查询的相关文章

MyBatis 多表联合查询及优化

序 这篇文章我打算来简单的谈谈 mybatis 的多表联合查询.起初是觉得挺简单的,没必要拿出来写,毕竟 mybatis 这东西现在是个开发的都会用,而且网上的文章也是一搜罗一大堆,根本就用不着我来重复.但是吧,就我前几天在做一个多表联合查询的时候,竟然出了很多意想不到的问题,而且这些问题的出现,并不是对 mybatis 不了解,而是在用的过程中会或多或少的忽略一些东西,导致提示各种错误. 背景 老规矩,开始之前,还是要先说说这件事的背景.也就是最近几天,公司要做一个后台的管理平台,由于之前的一

MyBatis 多表联合查询及优化 以及自定义返回结果集

下面就来说一下 mybatis 是通过什么来实现多表联合查询的.首先看一下表关系,如图: 这 里,我已经搭好了开发的环境,用到的是 SpringMVC + Spring + MyBatis,当然,为了简单期间,你可以不用搭前端的框架,只使用 Spring + MyBatis 就可以,外加 junit 测试即可.环境我就不带大家搭了,这里只说涉及到联合查询的操作. 设计好表之后,我用到了 mybatis 的自动生成工具 mybatis generator 生成的实体类.mapper 接口.以及 m

两个表联合查询获取聊天表中用户最新的一条聊天数据

一个用户表,一个聊天记录表,两个表联合查询获取聊天表中用户最新的一条聊天数据 select c.contentfrom sixin as c where c.tid = a.user_idorder by ctime desc limit 0,1) as content,(select c.statusfrom sixin as c where c.tid = a.user_idorder by ctime desc limit 0,1) as status from users as a, s

MySQL DML操作--------多表联合查询实战

1. 背景 * 多表联合查询是把不同表的记录到一起的一种方式 * 在SQL标准中规划的联合(join)大致分内连接,外连接,全连接.其中外连接又分左外连接,右外连接. 2. 内连接例子 (inner join) [ 员工 --> 部门 ] * 查看员工表[ employees ]和部门表[ departments ]结构 mysql> desc employees; +-----------+---------------+------+-----+---------+------------

对于多表联合查询的一点理解

操作数据库时多表联合查询很常见.也知道常见联合查询的集中类型,内连接.外连接.全连接.自连接,外连接又分为左连接和右连接. 这些概念我一直都知道,但对于感念的理解并不透彻.对于不同类型的联合查询的结果数据集合没有清晰的区分.前两天,工作中又遇到的这样的问题,才开始弄明白. 内连接:传统写法:select a.*,b.* from a,b where a.column=b.column; 新式写法:select a.* from a inner join b on a.column=b.colum

MVC5+EF6简单实例---以原有SQLServer数据库两表联合查询为例

工具:VS.net2013.EF6.MVC5.SQLServer2008 参考出处: http://www.cnblogs.com/slark/p/mvc-5-get-started-create-project.html http://www.cnblogs.com/miro/p/4288184.html http://www.cnblogs.com/dotnetmvc/p/3732029.html 一.准备工作 在SqlServer上创建数据库:Element 模拟两个表并插入数据:SysU

hibernate实现多表联合查询

以前用sql实现联合查询 是非常简单的事,只需要写sql语句就可以,第一次遇到hibernate要实现多表联合查询的时候还楞了一下.最后看了下资料,才恍然大悟,hibernate实现多表联合查询跟SQL没多大差别. hibernate很多实现都是靠喜欢配关系,但是如果两张表,数据量都非常大的时候,并不合适配关系. 例如:student表和score表需要做联合查询. 1)sql: select s.id,s.name,sc.score from student as s,score as sc

Dynamic CRM 2013学习笔记(九)CrmFetchKit.js介绍:Fetchxml、多表联合查询, 批量更新

CrmFetchKit.js是一个跨浏览器的一个类库,允许通过JavaScript来执行fetch xml的查询,还可以实现批量更新,分页查询等.目前已支持Chrome 25, Firefox 19 和 IE9/10 . 它的最大优势是可以通过fetchxml 来查询,这样我们就可以实现真正的多表联合查询,虽然可以用OData终结点的$expand来进行多表的联合查询,但这种方式没办法过滤多表的条件,它只能过滤主表的条件. 下面来看下简单的多表查询的例子: 1.首先定义一个fetchxml: 1

获取多表联合查询的存储过程。

USE [NopV3.3Test] GO /****** Object: StoredProcedure [dbo].[GetPostList] Script Date: 06/18/2014 15:27:19 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: 于留洋 -- Create date: 2014/06