Mybatis高级映射、延迟加载、查询缓存

高级映射:
    一对一的查询、一对多的查询、多对多的查询
    延迟加载
查询缓存:
    一级缓存
    二级缓存
mybatis和Spring的整合
逆向工程
数据模型的分析思路:
    1、每张表记录的数据内容
        分模块对每张表记录的内容进行熟悉,相对于学习系统需求(功能)的过程
    2、每张表数据库重要字段的设置
        非空字段、外键字段
    3、数据库级别表与表之间的关系
        外键关系
    4、表与表之间的业务关系
        在分析表与表之间的业务关系时一定要建立在某个业务意义的基础之上
数据模型的分析:
    在分析表与表之间的业务关系的时候需要建立在某个业务意义基础上去分析
    先分析数据库级别之间有关系的表之间的业务关系
SQL语句:
    确定查询的主表:订单表
    确定查询的关联表:用户表
        关联查询使用内连接还是外连接
        由于orders表中有一个外键(user_id),根据主键只能查一条记录,使用内连接
        通过外键关联查询用户表的时候只能查到一条记录
        外键等于父表的主键
        select 表1.*,表2.xxx,表2.xxx from 表1,表2 where 表1.xxx=表2.xxx
    创建pojo
        将上边SQL查询的结果映射到pojo中,pojo中必须包括所有查询列名
        原始的Orders.java不能映射全部的字段,需要新创建一个pojo
        创建一个pojo继承包括查询字段较多的po类(看字段需要)
ResultMap:当存在多列组成唯一标识的话,需要配置多个id
association:用于映射关联查询单个对象的信息
    property:要将关联查询的用户信息映射到Orders中哪个属性
    id:关联查询的用户的唯一标识
        column:指定唯一标识用户信息的列
        JavaType:映射到pojo的哪个属性
实现一对一查询:
    resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,
    即可完成映射,如果没有查询结果的特殊要求建议使用resultType
    resultMap:需要单独定义resultMap,实现有点麻烦,如果有对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射到pojo的属性中
resultMap可以实现延迟加载,resultType无法实现延迟加载
    resultMap中可以通过extend进行继承自定义的部分
表的内连接查询,表1的外键等于主表2的主键
实例:
    要求:
        对orders映射不能出现重复记录
        在orders.java类中添加List<orderDetail> orderDetails属性
        最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中
        映射成的orders记录数(orders信息不重复)
        每个orders中的orderDetails属性存储了该订单所对应的订单明细
mybatis使用collection对关联查询的多条记录映射到一个list集合属性中
    一个订单关联查询出了多条明细,要使用collection进行映射
    collection:
        property:将关联查询到的多条记录映射到哪个属性
        ofType:指定要映射到list集合属性中pojo的类型
        id:要映射的订单明细的唯一标识,没有明细添加一个明细,可以通过使用别名
        property:要将订单明细的唯一标识映射到pojo对象的属性
多对多的查询:
    查询用户及用户购买商品信息明细清单(用户名、用户地址、购买商品的名称、购买商品的时间、购买商品的数量)
        针对上面的需求使用resultType将查询到的记录映射到一个扩展的pojo中,很简单实现明细清单的功能
    一对多是多对多的特例
使用resultType还是resultMap
    使用resultMap是针对那些对查询结果映射有特殊要求的功能,比如特殊要求映射成list中包括多个list

resultMap总结:
    resultType:
作用:
    将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:
    常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。

resultMap:
    使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。

association:
作用:
    将关联查询信息映射到一个pojo对象中。
场合:
    为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。
    使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。
    
collection:
作用:
    将关联查询信息映射到一个list集合中。
场合:
    为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。
    如果使用resultType无法将查询结果映射到list集合中。
    
延迟加载:
    什么是延迟加载?
        resultMap可以实现高级映射(association、collection可以实现一对一、一对多的映射)
        association、collection具备延迟加载的功能
        如果查询订单并且关联查询用户信息,如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息,把对用户信息的按需去查询就是延迟加载
    延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快
    使用association实现延迟加载:
        查询订单并且关联查询用户信息
    mapper.xml
        需要定义两个mapper的方法对应的statement
        1、只查询订单信息
            查询订单的statement中使用association去延迟加载下边的statement(关联查询用户信息)
        2、通过上边查询到的订单信息中的user_id去关联查询用户信息    
    测试思路:
        1、执行mapper方法(findOrdersUserLazyLoading),内部去调用OrdersMapperCustom中的findOrdersUserLazyLoading
        只查询Orders信息(单表)
        2、在程序中去遍历上一步查询出的List<orders>,当我们调用orders中的getUser方法时,开始延迟加载
        3、延迟加载,调用UserMapper.xml中的findUserById方法获取用户信息
延迟加载的配置:
    mybatis默认没有开启延迟加载
    需要在SqlMapConfig中进行配置settings
        lazyLoadingEnabled  懒加载(延迟加载)改成true
        aggressiveLazyLoading   积极加载    改成false
不使用mybatis提供的association、collection中的延迟加载功能,如何实现延迟加载?
    定义两个mapper的方法
        查询订单的列表
        根据用户id查询用户信息
    实现思路:
        先去查询第一个mapper的方法,得到订单信息列表
        在程序中(service),按需去调用第二个mapper方法去查询用户信息
使用延迟加载的方法,先去查询简单的SQL(最好是单表,也可以是关联),再去按需加载关联查询的其他信息

查询缓存:
    什么是查询缓存:
        查询缓存是mybatis提供的用于减轻数据库的压力、提高数据库的性能
        mybatis提供一级缓存、二级缓存
        一级缓存:
            一级缓存是sqlsession级别的缓存
            在操作数据库时,需要构造sqlsession对象,在对象中有一个数据结构(hashmap)用于存储缓存数据
            不同的sqlsession的缓存数据的区域是一个hashmap的结构是互不影响的
        二级缓存:
            二级缓存是mapper级别的缓存
            多个sqlsession去操作同一个mapper的SQL语句,多个sqlsession去操作数据库得到的数据会存在二级缓存区域
            二级缓存是跨sqlsession的
            多个sqlsession可以共用二级缓存
    为什么要用缓存?
        缓存中有数据,就不用从数据库中获取,提高系统的响应速度、性能
    一级缓存:
        一级缓存的工作原理:
            hashmap
            第一次发起查询用户id为1的用户信息,先去缓存中找id为1的用户信息,然后去数据库查询id为1的用户信息
                得到用户信息后,将用户信息存到一级缓存中去
            如果sqlsession去执行commit操作的时候,会清空sqlsession当中的一级缓存,这样做的目的为了让缓存中永远存储的是最新的信息,避免脏读
            第二次发起查询用户id为1的用户信息,先去缓存中找是否有id为1的用户信息,发现缓存中有,直接从缓存中获取用户信息
        一级缓存的测试:
            mybatis默认支持一级缓存,不需要在配置文件中开启一级缓存开关
            按照上边的一级缓存的原理、步骤去测试
        一级缓存的应用:
            正式开发,是将mybatis和Spring进行整合开发,事务控制在service中,一个service方法中包含很多mapper方法调用
            service开始执行时,开启事务,创建sqlsession对象,只要方法结束,sqlsession关闭,用的是一个sqlsession
            如果是执行两次调用service方法,查询两次用户的信息,不走一级缓存,因为session方法结束,sqlsession就关闭,一级缓存就清空
    二级缓存:
        二级缓存的原理:
            sqlsession去查询用户为1的用户信息,查询到用户信息之后,会将查询的数据存储到二级缓存之中,首先要开启mybatis的二级缓存
            如果sqlsession3去执行相同mapper下的SQL,执行commit提交,就会清空该mapper下的二级缓存区域
            sqlsession2去查询用户为1的用户信息时,先去缓存中找是否存在数据,如果存在数据就直接在缓存中取出数据
        二级缓存与一级缓存的区别:
            二级缓存的范围比一级缓存更大,多个sqlsession可以共享一个Mapper二级缓存区域
            每一个Mapper都有一个自己二级缓存区域(按照namespace分)
            每一个namespace的Mapper有一个二级缓存区域,两个Mapper的namespace相同,这两个Mapper执行SQL查询到数据将存在相同的二级缓存区域中
        开启二级缓存:
            mybatis的二级缓存是mapper级别的,除了在SqlMapConfig设置二级缓存的总开关外,还要在具体的mapper.xml中开启二级缓存
            在UserMapper.xml中开启二级缓存,UserMapper.xml下的SQL执行完成会存储到他的缓存区域(HashMap)
            在mapper中开启二级缓存的方法,添加一个<cache/>标签
            调用pojo类,实现序列化接口,为了将缓存数据取出,执行反序列化操作,存储介质不一定在内存
        测试方法:
            Cache Hit Ratio [com.mybatis.mapper.UserMapper]: 0.5
            查找二级缓存,找了两次,命中率为0.5
            在查询的标签中添加useCache属性,设置为false,那么查询的时候将不调用缓存
        总结:
            针对每次查询都需要更新的数据SQL,我们要设置useCache=false表示禁用二级缓存
        刷新缓存:
            可以理解成就是清空缓存
            flushCache:刷新缓存
            总结:
                一般情况下执行完commit操作,都需要刷新缓存,flushCache=true表示刷新缓存,避免数据库的脏读
        刷新间隔:
            每隔一段时间自动清空缓存
    mybatis整合ehcache:
        ehcache是一个分布式的缓存框架,对缓存数据集中管理
        分布式缓存:
            提高系统的并发、性能等,都需要对系统进行分布式部署(集群部署方式)
            不使用分布式缓存的话,缓存数据就在各个服务器单独存储,不方便系统开发,所以要使用分布式缓存,对缓存数据进行集中管理
        mybatis无法对分布式的缓存进行管理,使用分布式框架对缓存数据进行集中管理(redis集群)(redis,memached,ehcache)
        mybatis需要和其他的分布式缓存框架进行整合,mybatis不是专业做缓存的,只是简单的把数据存进去了
        整合方法:
            mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,就实现这个cache接口开发即可
            mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类
            mybatis默认支持的cache实现类:PerpetualCache
        加入ehcache的包
        整合ehcache,配置mapper中cache标签的type为ehcache的实现cache的接口类型
        加入ehcache的配置文件
            在classpath下配置ehcache.xml
        测试:
            重新执行测试程序
    二级缓存在实际使用的时候,需要自己去配置
    二级缓存的应用场景:
        对于访问请求多,查询多的,并且要求实时性不高的可以用二级缓存,查询特别耗时的SQL,用户要求的实时性不高,可以将耗时的SQL用二级缓存
        设置刷新频率,多长时间,设置时间根据需要来确定
        开始用户在数据库取,后面都是在二级缓存取数据
    二级缓存的局限性:
        需求:
            商城的商品信息,缓存存储商品信息,当第一个用户查询的信息存入缓存,第二个用户查询的信息也存入,当用户数目足够多时,有用户执行了提交操作,
            那么二级缓存就全部清空,就要重新在数据库查询,缓存的命中率低
        mybatis对细粒度缓存实现不好(就是只针对一个改缓存),mybatis实现不了,需要自己手动实现业务层缓存,三级缓存
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容