前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MyBatis+Spring MVC开发指南(二)前言高级映射延迟加载查询缓存MyBatis和Spring整合逆向工程

MyBatis+Spring MVC开发指南(二)前言高级映射延迟加载查询缓存MyBatis和Spring整合逆向工程

作者头像
用户2890438
发布2018-08-21 09:49:38
5460
发布2018-08-21 09:49:38
举报

前言

《MyBatis+Spring MVC开发指南(一)》,本篇博客将涵盖MyBatis高级映射(一对一,一对多、多对多)、延迟加载、缓存原理分析(一级缓存、二级缓存)、MyBatis和Spring的整合、逆向工程等主题。

高级映射

由于在上一篇博客中已经带大家了解了MyBatis的一些基础知识,这里的高级映射将采用Mapper代理开发方式,主要分析Mapper.xml的高级映射写法。

表:

表之间的关系

用户表User和订单表Orders是一对多的关系; 订单表Orders和订单明细表OrderDetail是一对多关系; 订单明细表OrderDetail和商品表Items是多对一关系;

一对一映射

分析:把订单以及该订单的用户信息也查询出来。 SQL层面好说,就是User和Orders的关联查询,关键是查询出来的结果如何映射?是用resultType,还是用resultMap呢? 如果使用resultType的话,显然我们的实体bean(User仅仅包含用户信息;Orders仅仅包含订单信息,没有User的引用)并不能接受关联查询的结果集,那么我们可以考虑使用OrdersQueryVO(比如说让它extends Orders,然后在加上一些User的属性)作为输出结果类型。 从上面你大致可以发现,resultType适应较简单的输出结果映射,MyBatis其实还提供了resultMap做复杂输出结果映射,比如数据库column列与字段名称不一致的映射,比如延迟加载,比如一对一,一对多,多对多等高级映射特性。

一对一映射

注意点: 第一,Orders实体对象需要有User的引用 第二,注意<association>标签中javaType必须要明确指明类型!

一对多

把订单及订单明细查询出来。 我们就考虑使用resultMap,显然这次是一对多关系(一个订单有多个订单明细)。

看一对多XML片段:

一对多映射

第一,在Orders中存在List<OrderDetail>属性。 第二,一对多使用的是<collection>标签,需要特别注意的是ofType属性,也就是需要明确指明集合对象中的类型。

多对多

其实多对多,就是<collection>和<association>的综合应用。 第一,User实体拥有List<Orders>,Orders实体拥有List<OrderDetail>,OrderDetail实体拥有List<Items>; 第二,ResultMap的编写,其实就是<collection>里面嵌套<collection>,<collection>里面嵌套<association>而已。 这里仅仅分析下映射思路,就不贴XML片段了。我想只要思路清晰,那么就会很简单。

延迟加载

所谓延迟加载,就是需要的时候才发出SQL去查询,在Hibernate中有延迟加载,MyBatis同样提供了这个功能。延迟加载需要借助<resultMap>标签完成。我们先从思路上分析下MyBatis的延迟加载: 第一,MyBatis是默认开启延迟加载的么?如果不是,那么显然应该进行延迟加载配置。 在MyBatis的全局核心配置文件SqlMapConfig.xml的<settings>中可以设置lazyLoadingEnabled以及aggressiveLazyLoading属性值。 第二,要实现延迟加载,就得进行SQL拆分。(你想想,如果我们的SQL都写在一起,DB要么执行,要么不执行,根本做不到按需查询,所以要延迟加载,就得拆分SQL。)那么怎么进行拆分呢? 在<resultMap>中的<collection>以及<association>标签中有select属性,也就是说当使用到了<collection>/<association>的时候才发出select属性对应的SQL。 第三,我们其实可以借助MyBatis去完成延迟加载,也可以自己实现延迟加载。怎么做呢?一句话,需要的时候,我们自己调用相应的Statement完成即可。

查询缓存

MyBatis是要和DB打交道的,那么自然涉及到数据查询缓存的问题,这有利于提高系统的查询效率。思考几个问题: 第一,我们知道操作DB的接口是SqlSession,那么当我们创建了SqlSession后,在这个SqlSession生命周期中,应该是可以缓存数据。比如在同一个SqlSession内部,我们发出2条相同的Statement,就可以考虑从缓存中取得数据。 第二,针对上面的SqlSession缓存,如果你稍微看一下源码,你会知道其实就是一个HashMap,KEY主要就是SqlSession+StatementId构成。 第三,既然是缓存,那么涉及到缓存和DB的数据一致问题,如果处理不好,很可能带来脏读!那么显然不仅仅是<select>需要操作SqlSession缓存呢,对于<insert>/<update>/<delete>也需要处理缓存。那么怎么处理呢?对于<insert>/<update>/<delete>的处理思路,有2种:要么更新缓存,要么清空缓存。MyBatis采取了很简单的做法,就是清空缓存! 第四,随着SqlSession的关闭,SqlSession缓存也就失效了,这也是所谓的一级缓存。还有一种缓存,是跨SqlSession的,即二级缓存。想一想,如果我们把namespace+statementId作为KEY呢?这将意味着,多个SqlSession来发出同一个Statement,可以从缓存中拿取数据。

一级、二级缓存原理图:

一级缓存、二级缓存

对于一级缓存而言,MyBatis是默认支持的,无需配置开启。而二级缓存是需要开启的,首先来说,需要在全局配置文件中指明(在<setting>中的cacheEnabled属性,全局性缓存开关),其次在需要开启二级缓存的XXXMapper.xml中指明(<cache>标签)。 MyBatis还提供了更加细粒度的缓存控制,比如在<select>标签中,就提供了useCache属性,默认为true,即使用二级缓存。(同理,<insert>标签中提供flushCache配置,显然,我们应该使用默认的true,去清空缓存) 虽然如此,但是MyBatis的二级缓存仍然不是很好用,为什么这么说呢? 假设,二级缓存中,有商品列表的数据,如果我们仅仅更新了其中一个商品,那么意味着二级缓存的清空。而我们真正想要的是刷新该商品的缓存信息而不要影响其他商品的缓存信息。

思考一个问题:缓存到哪里去呢?

缓存到本机的内存?磁盘?能够支持分布式缓存么,如ehcache、Redis? 如果你是MyBatis的作者,显然你应该提供一个Cache接口,让使用方可以自己选择缓存的具体实现! 这里,我们还需要特别注意的是,缓存对象的序列化、反序列问题(如果缓存到Redis中,那么显然涉及网络通信IO呢),应该实现Serializable接口。

看一眼MyBatis提供的Cache接口:

Cache接口

MyBatis的默认实现类:

默认Cache实现类

假设,我们需要整合ehcache的话,那么具体需要做什么呢? 第一,提供ehcache以及ehcache与MyBatis整合的依赖 第二,在<cache/>标签中,type属性指明ehcache实现Cache接口的实现类 第三,提供相关的ehcache配置文件

MyBatis和Spring整合

整合的思路(需要MyBatis-Spring整合的依赖,由MyBatis提供): 第一,SqlSessionFactory需要交给Spring管理(单例) 注意到SqlSessionFactory的创建显然需要数据库连接相关的信息,因此需要数据库连接池;除此之外还需要MyBatis的主配置文件。 第二,如果采用原始DAO的开发方法的话,那么我们是需要向Dao的实现类(交给Spring管理)中注入SqlSessionFactory,然后在各个方法中得到SqlSession进行操作的。可以让Dao的实现类extends SqlSessionDaoSupport,而SqlSessionDaoSupport类中已经存在setSqlSessionFactory()方法,因此我们可以直接向Dao的实现类注入SqlSessionFactory;另外SqlSessionDaoSupport中有SqlSession,因此使得操作更加简单呢;而且都交给Spring管理了,我们自然不必担心SqlSession的关闭忘了。 第三,如果采用Mapper代理的方式开发,那么我们需要Spring做的就是管理Mapper动态代理实现。

基于Mapper代理开发的XML片段:

Spring配置文件

我们可以指定一个包路径,告诉Spring,将这个路径下的Mapper接口+Mapper.xml都注册一下生成代理对象进行管理。

逆向工程

什么是逆向工程,说白了,就是MyBatis为我们提供了一个自动代码生成工具,这个工具可以根据数据库表信息,帮助我们生成Mapper.java/Mapper.xml/POJO实体类。 Mybatis提供了多种生成的方式,比较普遍的就是根据一个XML配置文件进行生成。在这个XML配置文件中指明DB连接信息,表信息,生成到哪里,包路径是什么等。 具体的例子,大家可以参考:http://www.mybatis.org/generator/ 进行操作即可。

到这里,这个系列文章,就写了一半了,下一篇将是关于Spring MVC~

Good Night!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.06.25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 高级映射
  • 延迟加载
  • 查询缓存
  • MyBatis和Spring整合
  • 逆向工程
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档