mybatis笔记 - 07

2017 06 18

多对一和一对多关系的查询应用

多对一

关联表查询:

提出需求:

以学生和班级为例 :
站在学生的角度上 多对一的关系 N......1
站在班级的角度上 一对多的关系 1......N
因此如果学生和班级分成两张表 需要将两张表进行关系关联
在关系型数据库中可以采取的方式:
    1.逻辑关联:
        并不利用数据库提供的工具对表与表之间进行操作
        程序编写人员在程序内对两个表的内容进行操作 通过代码进行联系的建立
        方便数据迁移 开发使用的第一选择
    2.物理关联:
        利用外键形式进行数据的关联 
        通过这种方式完成多对一的表示   外键永远在多的一方
采取物理关联 需要进行外键设置 如下图:
image
那么 在java当中怎么来表示多对一的关系呢?
同样的逻辑 在 “多” 的一方 建立 “一” 的一方的对象属性
image

现在要查询学生信息并带回班级信息(class_name)

假设给定学生ID(studeny_id)

需要新建ClassInFo.java文件和Student.java文件
新建 Studentmapper.xml  和 ClassInFomapper.xml文件
更改主配置文件 mybatis-config.xml  和  log4j.properties

Studenmapper.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.shxt.model.Student">
    <resultMap type="Student" id="BaseResultMapperStudent">
        <id column="student_id" property="student_id" />
        <result column="student_name" property="student_name" />
        <result column="sex" property="sex" />
    </resultMap>
</mapper>

ClassInFomapper.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.shxt.model.ClassInfo">
    <resultMap type="ClassInfo" id="BaseResultMapperClassInFo">
        <id column="class_id" property="class_id" />
        <result column="class_name" property="class_name" />
    </resultMap>
</mapper>

mybatis-config.xml文件添加mapper映射文件的引用路径

<mappers>
    <mapper resource="com/shxt/model/StudentMapper.xml"/>
    <mapper resource="com/shxt/model/ClassInFoMapper.xml"/>
</mappers>

log4j.properties属性文件内添加sql语句显示所必需的命名空间

log4j.logger.com.shxt.model.Student=TRACE
log4j.logger.com.shxt.model.ClassInFo=TRACE

为了能够保存查询出来的Class的ID 需要在Student.java类中新增一个属性 并在Studentmapper.xml中表明

Student.java :

    private Integer class_id;

    public Integer getClass_id() {
        return this.class_id;
    }
    public void setClass_id( Integer class_id ) {
        this.class_id = class_id;
    }

Studentmapper.xml :

 <resultMap type="Student" id="BaseResultMapperStudent">
        <id column="student_id" property="student_id" />
        <result column="student_name" property="student_name" />
        <result column="sex" property="sex" />
        <result column="class_id" property="class_id" />
</resultMap>

传统方式:

mapper映射文件语句示例:

Studentmapper.xml

<sql id="student_base_columns">
    student_id,student_name,sex,user_name
</sql>
<select id="select01" parameterType="_int" resultMap="BaseResultMapperStudent">
     SELECT
     <include refid="student_base_columns"/>
    FROM
        student
    WHERE
        student_Id=#{student_id}
</select>

ClassInFomapper.xml

<sql id="ClassInFo_base_columns">
    class_id,class_name
</sql>
<select id="get01" parameterType="_int" resultMap="BaseResultMapperClassInFo">
     SELECT
        <include refid="class_base_columns"/>
    FROM
        classinfo
    WHERE
        class_Id=#{class_id}
</select>

测试用例书写:

    @Test
public void tesMethod01(){
    SqlSession sqlsession = null;
    try {
        sqlsession = MyBatisUtils.getSqlSession();
        //首先进行查询  拿到下一步查询必须的class_id
        Student student = sqlsession.selectOne(Student.class.getName()+".select01",1);
        //进行判断   利用class_id进行班级信息的查询
        if(student.getClass_id()!=null){
            ClassInFo classInFo = sqlsession.selectOne(Class.class.getName()+".get01",student.getClass_id());
            //将查询出来的classInFo对象添加到student对象中
            student.setClassInFo(classInFo);
        }
        //调用toString()进行输出
        System.out.println(student);
    } finally {
        MyBatisUtils.closeSqlSession(sqlsession);
    }
}

select方式:

Studentmapper.xml:

<resultMap type="Student" id="BaseResultMapperStudent">
    <id column="student_id" property="student_id" />
    <result column="student_name" property="student_name" />
    <result column="sex" property="sex" />
    <result column="class_id" property="class_id" />
    <association property="calssInFo" javaType="ClassInFo" column="class_id" select="com.shxt.model.ClassInFo.get01"/>
        <!--  <association>     关联对象的标签    property 属性名   javaType  这里因为是自定义类 所以采用别名方式   column建立联系的字段名(关键)  select  去执行哪个命名空间的哪条语句(定位)-->
</resultMap>
 <select id="select01" parameterType="_int" resultMap="BaseResultMapperStudent">
     SELECT
        <include refid="student_base_columns"/>
    FROM
        student
    WHERE
        student_Id=#{student_id}
</select>

测试用例书写:

    @Test
public void tesMethod02(){
    SqlSession sqlsession = null;
    try {
        sqlsession = MyBatisUtils.getSqlSession();
        Student student = sqlsession.selectOne(Student.class.getName()+".select01",1);
        System.out.println(student);
    } finally {
        MyBatisUtils.closeSqlSession(sqlsession);
    }
}
如果编写完成select方式 再用传统方式查询相同sql语句 将会产生三条查询语句(第一次执行之后 会因为缓存原因 log4j显示两条语句)
对此 mybatis提供了<resultMap>标签的继承 使用extends属性 将内置对象与关联对象分离 按照需求 如果需要用到关联对象 就调用集成后的<resultMap>标签

代码示例:
Studentmapper.xml

<resultMap type="Student" id="BaseResultMapperStudent">
    <id column="student_id" property="student_id" />
    <result column="student_name" property="student_name" />
    <result column="sex" property="sex" />
    <result column="class_id" property="class_id" />
</resultMap>

<resultMap type="Student" id="BaseResultMapperStudentByObject" extends="BaseResultMapperStudent">
    <association property="calssInFo" javaType="ClassInFo" column="class_id" select="com.shxt.model.ClassInFo.get01"/>
</resultMap>

连接查询方式:

mapper映射文件添加如下内容:


image
使用左外链接的方式   其实也可以进行两个表的查询,例如
SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=1;
(这个语句我瞎写的   —— . —— )
image

测试代码示例:

@Test
public void tesMethod03(){
    SqlSession sqlsession = null;
    try {
        sqlsession = MyBatisUtils.getSqlSession();
        Student student = sqlsession.selectOne(Student.class.getName()+".query",1);
        System.out.println(student);
    } finally {
        MyBatisUtils.closeSqlSession(sqlsession);
    }
}

如果想进行多条记录的查询

需要将mapper文件中的where条件子句删掉

在测试用例中使用selectlist方法查询

返回List<Object>类型的值 再进行下一步处理

简单扩展 DTO POJO VO BO PO

同样的实体化类 处在不同的思想和场景下 针对于不同的目的 就有了这些名词的区别

一对多

依然以上述为例

上文介绍站在学生角度看的“多对一”关系的处理

现在尝试站在教室角度 来解决“一对多”关系的处理

在上文中 我们进行的实例化 仅仅是针对于学生和教室来做的

多个学生对象可以对应一个教室对象

我们需要在学生的持久化对象内建立教室对象的id属性 在数据库中建立主键联系 进而运用DTO对象或者select方式 连接查询方式来拿到教室对象的详细内容

现在我们转换思路 将“多对一”转化为“一对多”

首先需要在class持久化对象内建立student对象

但是由于是“一对多”关系 一个class对象会对应多个student对象 我们需要创建一个List<Student>类型的对象来进行查询结果的存储

同样在sudent实体化类中 依然存在 class_id 属性 依然可以进行一对一的查询

可以使用<collection>标签来进行“一对多”关系的查询处理

<resultMap type="ClassInfo" id="simple01" extends="BaseResultMapper">
<!-- collection标签 
    property指代类中属性名   在这里代表类中的studentList集合 
    javaType可以忽略不写让Mybatis来进行自动处理也可简写为list
    ofType在集合中存的是什么类型   
    column指代用哪个字段进行下一步查询
    select用来进行定位下一步动作的命名空间内的sql语句
-->
    <collection property="studentList" javaType="java.util.List" ofType="Student"
     column="class_id"  select="com.shxt.model.Student.select01"/>
</resultMap>

在两个映射文件中的代码如下图所示

重点是<collection>标签的运用

在测试文件中测试用例的书写为一般测试格式
故不予示范


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Java数据持久化之mybatis 一. mybatis简介 1.1 原始的JDBC操作: Java 通过 Jav...
    小Q逛逛阅读 4,896评论 0 16
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,573评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 一. Java基础部分.................................................
    wy_sure阅读 3,788评论 0 11
  • 暮江怀雪,宛如柳絮纷飞,何处寻她?生活在南方的我,不曾见过雪。 红尘旧梦,窗外雪声,凌空而落。帘卷轻轻摇动,微光...
    山涧雨律阅读 643评论 0 1