mybaits延迟加载原理_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 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中的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中开启二级缓存的方法,添加一个标签

调用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实现不了,需要自己手动实现业务层缓存,三级缓存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值