mybatis-notes:写一个简单的demo-mybatis的懒加载(延迟加载)

1. 认识一蛤什么是懒加载

什么是懒加载?所谓懒加载,简单说就是按需加载,用于查询结果存在一对一或一对多的情况,在mybatis中体现在<association>和<collection>的参数中,当要不用到这种关系的数据的时候就不向数据库查询,要用的时候才再次发送一条语句来查询,这样大大节省了数据库资源也提高了查询效率。

2. 便于理解,来个场景

上面的介绍也是很多网上很多人的说法,这样就太笼统、抽象了,举个例子:
比如我的demo中的Teacher类中属性有
t_id(int型),
t_name(String型),
stuList(List型),
其中stuList顾名思义既是这个老师教的学生的集合。
而Student类是对应的student表,里面的属性有
id(int型),
stu_name(String型),
age(int型),
t_id(int型),
其中student表中的t_id和teacher表中的t_id是对应的。
那么懒加载就来了,如果我要查询这个老师的所有信息,但是现在我还不想看他到底教哪些学生,那么后台就会先查询这个老师的除了学生表之外的信息。当我要看这个老师到底教了哪些学生时,再向数据库发送一条sql单独查询哪些学生的属性带有这个老师的t_id。

3. 具体代码实现

要用到懒加载,就要多用到两个jar包,asm和cglib:

jar

导了jar后,需要在总config.xml中进行一些配置:

    <settings>
        <!-- 日志 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
        <!-- 打开延迟加载的开关 -->
        <setting name="lazyLoadingEnabled" value="true" />
        <!-- 将积极加载改为消极加载即按需要加载 -->
        <setting name="aggressiveLazyLoading" value="false" />
    </settings>

其中懒加载相关的配置只有后两行,不过第一行的日志有助于跟进mabatis的执行。

然后dao中写好接口TeacherDao.java

package demo.cyj.dao;
import demo.cyj.pojo.Teacher;
public interface TeacherDao {
    public Teacher findTeacherByTname(String tname);    
}

后面就是重头了,mapperTeacherMapper.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="demo.cyj.dao.TeacherDao">
    <select id="findTeacherByTname" resultType="Teacher" resultMap="getTeacher">
        select t.t_id t_id,t.t_name t_name from teacher t where t.t_name =#{name}
    </select>

    <resultMap type="Teacher" id="getTeacher">
        <collection ofType="Student" property="stuList" fetchType="lazy" column="t_name" select="findTeacherByTnameLazy" />
    </resultMap>

    <select id="findTeacherByTnameLazy" resultType="Student" >
        select s.id id,s.stu_name stu_name,s.stu_age age,s.t_id t_id from student s left join teacher t on t.t_id = s.t_id where t.t_name=#{name} 
    </select>       
</mapper>

可以看到,这个有懒加载的查询分为了两个<select>和一个<resultMap>,
如果你的表字段和类的属性名不同,可以通过取别名或在<resultMap>中额外做字段匹配的配置),
<resultMap>中的<collection>就是配置一对多关系的标签,
<association>是一对一的标签),
在<collection>中,

  • ofType="Student"指定了这个集合的存放(组装对象)类型,类似泛型;
  • property="stuList"指定了这个集合在Teacher类中的属性名;
  • fetchType="lazy"指定了哪种加载方式;
  • column="t_name"指定了上一条sql中查询出来的结果中的哪一列的值会被传递到下一条sql中作为条件值;
  • select="findTeacherByTnameLazy"指定了下一条被执行的<select>的id名;

而在第二条<select>中就要将id和上一条的select中配置的名字一致,resultType="Student"指定了查询结果组装为Student类对象。

最后写测试类Test.java

package demo.cyj;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import demo.cyj.dao.StudentDao;
import demo.cyj.dao.TeacherDao;
import demo.cyj.pojo.Student;
import demo.cyj.pojo.Teacher;

public class Test { 
    public static void main(String[] args) throws IOException {
        String src = "config.xml";
        InputStream inputStream = Resources.getResourceAsStream(src);
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sessionFactory.openSession(true);
        
        //绑定
        TeacherDao td = sqlSession.getMapper(TeacherDao.class);
        Teacher t= td.findTeacherByTname("htc");
        System.out.println(t.getT_id());
    }
}

运行后可以看到控制台打印的结果:

只展示id的情况

这是因为这段代码System.out.println(t.getT_id());,我只想看这个名为htc的老师的id是多少,所以只向数据库发送了一条sql,没有去查stuList的信息。

然后修改代码:
public class Test { 
    public static void main(String[] args) throws IOException {
        String src = "config.xml";
        InputStream inputStream = Resources.getResourceAsStream(src);
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sessionFactory.openSession(true);
        
        //绑定
        TeacherDao td = sqlSession.getMapper(TeacherDao.class);     
        Teacher t= td.findTeacherByTname("htc");
        System.out.println(t);
    }
}

修改的代码为System.out.println(t);,即打印该名为htc的老师的所有信息,包括stuList.
运行后可以看到控制台打印的结果:

展示所有数据的情况

控制台信息太长没显示完,附一个控制台信息:

==>  Preparing: select t.t_id t_id,t.t_name t_name from teacher t where t.t_name =? 
==> Parameters: htc(String)
<==    Columns: t_id, t_name
<==        Row: 1, htc
<==      Total: 1
==>  Preparing: select s.id id,s.stu_name stu_name,s.stu_age age,s.t_id t_id from student s left join teacher t on t.t_id = s.t_id where t.t_name=? 
==> Parameters: htc(String)
<==    Columns: id, stu_name, age, t_id
<==        Row: 8, 黑拐, 43, 1
<==        Row: 9, 拐, 50, 1
<==        Row: 10, 拐棍, 50, 1
<==        Row: 11, 大黑拐, 30, 1
<==        Row: 12, 小黑拐, 12, 1
<==        Row: 13, 拐哥, 29, 1
<==        Row: 14, 胡黑拐, 123, 1
<==      Total: 7
Teacher [t_id=1, t_name=null, stuList=[Student [id=8, stu_name=黑拐, age=43, t_id=1], Student [id=9, stu_name=拐, age=50, t_id=1], Student [id=10, stu_name=拐棍, age=50, t_id=1], Student [id=11, stu_name=大黑拐, age=30, t_id=1], Student [id=12, stu_name=小黑拐, age=12, t_id=1], Student [id=13, stu_name=拐哥, age=29, t_id=1], Student [id=14, stu_name=胡黑拐, age=123, t_id=1]]]

可以看到,这次的sql语句有两条了,一次是查询该老师的基本信息,一次是查询该老师教的学生的列表。


总结一下:

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

推荐阅读更多精彩内容