MyBatis学习总结第三章节

实现关联表查询续

一对一关联:

这里我们假设一个老师只负责教一个班级,那么老师和班级之间的关系就是一种一对一的关系。
那么我们可以创建一张教师表班级表

CREATE TABLE teacher(
     t_id INT PRIMARY KEY AUTO_INCREMENT, 
     t_name VARCHAR(20)
 );
 CREATE TABLE class(
     c_id INT PRIMARY KEY AUTO_INCREMENT, 
     c_name VARCHAR(20), 
     teacher_id INT
 );
ALTER TABLE class ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES teacher(t_id);    

INSERT INTO teacher(t_name) VALUES('teacher1');
INSERT INTO teacher(t_name) VALUES('teacher2');

INSERT INTO class(c_name, teacher_id) VALUES('class_a', 1);
INSERT INTO class(c_name, teacher_id) VALUES('class_b', 2);

表之间的关系如下图:
这里写图片描述

定义实体类:

1.Teacher类,Teacher类是teacher表对应的实体类。

//定义实体类的属性,与teacher表中的字段对应
private int id;            //id===>t_id
private String name;       //name===>t_name
//省略部分代码

2.Classes类,Classes类是class表对应的实体类

//定义实体类的属性,与class表中的字段对应
private int id;            //id===>c_id
private String name;       //name===>c_name
/**
*class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性,
*用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的
*/
private Teacher teacher;
//省略部分代码

定义sql映射文件classMapper.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="me.gacl.mapping.classMapper">
<!--查询方式一:嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集
              封装联表查询的数据(去除重复的数据)
              select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=1-->
    <select id="getClass" parameterType="int"
            resultMap="ClassResultMap">
        select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id =#{id}
    </select>
    <resultMap type="me.gacl.domain.Classes" id="ClassResultMap">
    <id property="id" columni=c_id"/>
    <result property="name" column="c_name"/>
        <association property="teacher" javaType="me.gacl.domain.Teacher">
            <id property="id" column="t_id"/>
            <result property="name" column="t_name"/>
        </association>
    </resultMap>

<!--查询方式二:嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型
              SELECT * FROM class WHERE c_id=1;
              SELECT * FROM teacher WHERE t_id=1  //1是上一个查询得到的teacher_id的值-->
    <select id="getClass2" parameterType="int" 
            resultMap="ClassResultMap2">
        select * from class where c_id=#{id}
    </select>       
    <resultMap type="me.gacl.domain.Classes" id="ClassResultMap2">
        <id property="id" column="c_id"/>
        <result property="name" column="c_name"/>
        <association property="teacher" column="teacher_id" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" parameterType="int" 
            resultType="me.gacl.domain.Teacher">
        SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
    </select>
</mapper>

在conf.xml文件中,注册classMapper.xml

<mappers>
        <mapper resource="me/gacl/mapping/classMapper.xml"/>
</mappers>

编写单元测试代码

@Test
public void testGetClass(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    String statement = "me.gacl.mapping.classMapper.getClass";
    Classes clazz = sqlSession.selectOne(statement,1);
    sqlSession.close();
    System.out.println(clazz);
    //打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1]]
}

@Test
public void testGetClass2(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    String statement = "me.gacl.mapping.classMapper.getClass2";
    Classes clazz = sqlSession.selectOne(statement,1);
    sqlSession.close();
    System.out.println(clazz);
    //打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1]]
}

一对多查询

在上面我们假设了一个老师只负责教一个班级,但一个班级会有多个学生,那么班级对于学生的关系就是一种一对多的关系。

CREATE TABLE student(
    s_id INT PRIMARY KEY AUTO_INCREMENT, 
    s_name VARCHAR(20), 
    class_id INT
);
INSERT INTO student(s_name, class_id) VALUES('student_A', 1);
INSERT INTO student(s_name, class_id) VALUES('student_B', 1);
INSERT INTO student(s_name, class_id) VALUES('student_C', 1);
INSERT INTO student(s_name, class_id) VALUES('student_D', 2);
INSERT INTO student(s_name, class_id) VALUES('student_E', 2);
INSERT INTO student(s_name, class_id) VALUES('student_F', 2);

在上面的一对一关联查询中我们已经创建了班级表和教师表,在创建一张学生表之后的关系图:
这里写图片描述

定义实体类

Student类,Student类是表student对应的实体类

private int id;            //id===>s_id
private String name;       //name===>s_name、
//省略部分代码

修改Classes类,添加一个List<Student>students属性,使用一个List<Student>集合属性表示班级拥有的学生,如下:

private int id;                 //id===>c_id
private String name;            //name===>c_name
private Teacher teacher;
//使用一个List<Student>集合属性表示班级拥有的学生
private List<Student> students;

修改sql映射文件classMapper.xml

添加如下的SQL映射信息:

<select id="getClass3" parameterType="int" 
        resultMap="ClassResultMap3">
    select * from class c, teacher t,student s where c.teacher_id=t.t_id and c.C_id=s.class_id and  c.c_id=#{id}
</select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap3">
    <id property="id" column="c_id"/>
    <result property="name" column="c_name"/>
    <association property="teacher" column="teacher_id" javaType="me.gacl.domain.Teacher">
        <id property="id" column="t_id"/>
        <result property="name" column="t_name"/>
    </association>
<!-- ofType指定students集合中的对象类型 -->
    <collection property="students" ofType="me.gacl.domain.Student">
        <id property="id" column="s_id"/>
        <result property="name" column="s_name"/>
    </collection>
</resultMap>


<select id="getClass4" parameterType="int" 
        resultMap="ClassResultMap4">
    select * from class where c_id=#{id}
</select>
<resultMap type="me.gacl.domain.Classes" id="ClassResultMap4">
    <id property="id" column="c_id"/>
    <result property="name" column="c_name"/>
    <association property="teacher" column="teacher_id" 
        javaType="me.gacl.domain.Teacher" select="getTeacher2"></association>
    <collection property="students" ofType="me.gacl.domain.Student" 
        column="c_id" select="getStudent"></collection>
</resultMap>

<select id="getTeacher2" parameterType="int" 
        resultType="me.gacl.domain.Teacher">
    SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
</select>

<select id="getStudent" parameterType="int" 
        resultType="me.gacl.domain.Student">
    SELECT s_id id, s_name name FROM student WHERE class_id=#{id}
</select>

编写单元测试代码

@Test
public void testGetClass3(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    String statement = "me.gacl.mapping.classMapper.getClass3";
    Classes clazz = sqlSession.selectOne(statement,1);//查询class表中id为1的记录
    sqlSession.close();
    //打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1], students=[Student [id=1, name=student_A], Student [id=2, name=student_B], Student [id=3, name=student_C]]]
    System.out.println(clazz);
}

@Test
public void testGetClass4(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    String statement = "me.gacl.mapping.classMapper.getClass4";
    Classes clazz = sqlSession.selectOne(statement,1);//查询class表中id为1的记录
    sqlSession.close();
    //打印结果:Classes [id=1, name=class_a, teacher=Teacher [id=1, name=teacher1], students=[Student [id=1, name=student_A], Student [id=2, name=student_B], Student [id=3, name=student_C]]]
    System.out.println(clazz);
}

总结:

MyBatis中使用collection标签来解决一对多的关联查询

collection标签可用的属性如下:
(1) property:对象属性的名称
(2) ofType属性指定集合中元素的对象类型
(3) column:所对应的外键字段名称
(4) select:使用另一个查询封装的结果


调用存储过程

存储过程的定义

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。

提出一个需求

  查询得到男性或女性的数量, 如果传入的是0就女性否则是男性

准备数据库表和存储过程

create table p_user(  
    id int primary key auto_increment,  
    name varchar(10),
    sex char(2)
); 

insert into p_user(name,sex) values('A',"男");  
insert into p_user(name,sex) values('B',"女");  
insert into p_user(name,sex) values('C',"男");  

-- 创建存储过程(查询得到男性或女性的数量, 如果传入的是0就女性否则是男性)
DELIMITER $
CREATE PROCEDURE mybatis.ges_user_count(IN sex_id INT, OUT user_count INT)
BEGIN  
IF sex_id=0 THEN
SELECT COUNT(*) FROM mybatis.p_user WHERE p_user.sex='女' INTO user_count;
ELSE
SELECT COUNT(*) FROM mybatis.p_user WHERE p_user.sex='男' INTO user_count;
END IF;
END 
$

-- 调用存储过程
DELIMITER ;
SET @user_count = 0;
CALL mybatis.ges_user_count(1, @user_count);
SELECT @user_count;

编辑userMapper.xml

在userMapper.xml文件中添加如下的配置项:

<!--查询得到男性或女性的数量, 如果传入的是0就女性否则是男性-->
<select id="getUserCount" parameterMap="getUserCountMap" 
        statementType="CALLABLE">
    CALL mybatis.ges_user_count(?,?)
</select>

<!--parameterMap.put("sexid", 0);
    parameterMap.put("usercount", -1);
-->
<parameterMap type="java.util.Map" id="getUserCountMap">
    <parameter property="sexid" mode="IN" jdbcType="INTEGER"/>
    <parameter property="usercount" mode="OUT" jdbcType="INTEGER"/>
</parameterMap>

编写单元测试代码###、

@Test
public void testGetUserCount(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    String statement = "me.gacl.mapping.userMapper.getUserCount";
    Map<String, Integer> parameterMap = new HashMap<String, Integer>();
    parameterMap.put("sexid", 1);
    parameterMap.put("usercount", -1);
    sqlSession.selectOne(statement, parameterMap);
    Integer result = parameterMap.get("usercount");
    System.out.println(result);
    sqlSession.close();
}

重点:###

1.其中DELIMITER 定好结束符为”$$”, 然后最后又定义为”;”, MYSQL的默认结束符为”;”. 默认情况下,delimiter是分号;
2.调用存储过程 delimiter定义结束符为”;” SET赋初始值, 使用CALL调用 ,SELECT作用是输出


Mybatis缓存

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持
1.一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
2. 二级缓存:二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
3.对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

如何开启二级缓存

开启二级缓存,只需要在userMapper.xml文件中添加如下配置:

<mapper namespace="me.gacl.mapping.userMapper">
<!-- 开启二级缓存 -->
<cache/>

二级缓存补充说明

  1. 映射语句文件中的所有select语句将会被缓存。
  2. 映射语句文件中的所有insert,update和delete语句会刷新缓存。
  3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。
  4. 缓存会根据指定的时间间隔来刷新。
  5. 缓存会存储1024个对象

cache标签常用属性:

<cache eviction="FIFO"  <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间60s-->
size="512"           <!--最多缓存512个引用对象-->
readOnly="true"/>   <!--只读-->
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值