Java应用学习(七)-回顾Mybatis和Spring MVC
一、Spring MVC回顾
1.1、Spring MVC的五大组件
1、DispatcherServlet
前端控制器
这个控件是
SpringMVC
最核心的一个控件,Spring MVC写好的一个Servlet,它是整个流程的控制中心,由它调用其他组件处理用户请求,DispatcherServlet
的存在降低了组件间的耦合。主要负责捕获来自客户端的请求及调度各个组件。
2、HandlerMapping
处理器映射器
HandlerMapping
负责根据用户请求找到Handler,即处理器,Spring MVC
提供了不同的映射器来实现不同的映射方式,例如:配置文件方式、实现接口方式、注解方式。**根据URL查找后端控制器 Handler **
3、Handler
处理器
即Controller,它是我们开发中要编写的具体业务控制器。由
DispatcherServlet
把用户请求转发到Handler。由Handler对具体的用户请求进行处理。负责处理前端请求,完成业务逻辑,生成
ModelAndView
对象后将结果返回给前端控制器
4、HandlerAdapter
处理器适配器
通过
HandlerAdapter
对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。调用后端控制器(Handler),拿到后端控制器返回的结果
ModelAndView
后将结果返回给前端控制器DispatcherServlet
。
5、View Resolver
视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名
即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。主要负责将从
DispatcherServlet
中拿到的ModelAndView
对象进行解析,生成View对象返回给DispatcherServlet
。
1.2、Spring MVC 的执行流程
执行流程图
客户端浏览器向前端控制器(
DispatcherServlet
)发出请求。DispatcherServlet
接收到请求后,调用处理器映射器(HandlerMapping
)。HandlerMapping
根据请求的url
查找对应的处理器(Handler
,也称后端控制器),返回处理器对象(Handler
),并且如果有处理器拦截器(HandlerInterceptor
)的话,会将处理器对象(Handler
)和处理器拦截器对象(HandlerInterceptor
)一并返回给DispatcherServlet
。DispatcherServlet
拿到这些信息后,会调用处理器适配器(HandlerAdapter
),HandlerAdapter
会调用Handler,Handler执行处理DispatcherServlet
发来的请求,生成ModelAndView
对象返回给HandlerAdapter
。HandlerAdapter
将ModelAndView
对象返回给DispatcherServlet
。DispatcherServlet
在拿到ModelAndView
对象之后,将ModelAndView
对象发给视图解析器(ViewResolver
)。ViewResolver
将ModelAndView
对象进行解析,生成View对象,将View对象返回给DispatcherServlet
。DispatcherServlet
拿到View对象,对jsp
页面进行渲染(将模型数据填充到视图中),将渲染后的页面呈现给用户。
二、Mybatis
回顾
2.1、Mybatis
的缓存机制
1、概述
Mybatis
包含了一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。Mybatis
系统中默认定义了两级缓存
2、一级缓存和二级缓存
- 默认情况下,只有一级缓存(
SqlSession
级别地缓存,也称为本地缓存)开启。 - 二级缓存(全局缓存)需要手动开启和配置,是基于
namespace
级别的缓存 - 为了提高扩展性。
Mybatis
定义了缓存接口 Cache 。我们可以通过实现 Cache 接口来自定义二级缓存
2.2、一级缓存
1、说明
与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中获取。
2、一级缓存失效的四种情况
SqlSession
不同SqlSession
相同,但查询条件不同SqlSession
相同,但两次查询期间执行了增删改操作SqlSession
相同,但手动清除了一级缓存
使用以下语句可以清除缓存
1 | openSession.clearCache(); |
3、缓存原理
一级缓存实际上是一个Map,定义如下:
1 | private Map<Object, Object> cache = new HashMap<Object, Object>(); |
2.3、二级缓存
1、说明
之所以称之为“二级缓存”,是相对于“一级缓存”而言的。既然有了一级缓存,那么为什么要提供二级缓存呢?我们知道,在一级缓存中,不同session进行相同SQL查询的时候,是查询两次数据库的。显然这是一种浪费,既然SQL查询相同,就没有必要再次查库了,直接利用缓存数据即可,这种思想就是MyBatis
二级缓存的初衷。
另外,Spring和MyBatis
整合时,每次查询之后都要进行关闭sqlsession
,关闭之后数据被清空。所以MyBatis
和Spring整合之后,一级缓存是没有意义的。如果开启二级缓存,关闭sqlsession
后,会把该sqlsession
一级缓存中的数据添加到mapper namespace的二级缓存中。这样,缓存在sqlsession
关闭之后依然存在。
二级缓存是Mapper级别的缓存,多个SqlSession
去操作同一个Mapper的sql
语句,多个SqlSession
可以共用二级缓存,二级缓存是跨SqlSession
的。
- 一个会话,查询一条数据,这个数据就会被存放在当前会话的一级缓存中;
- 如果会话关闭,一级缓存中的数据就会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存
2、使用
- 开启全局二级缓存配置,在
mybatis
全局配置文件中添加以下配置
1 | <setting name="cacheEnabled" value="true" /> |
- 在
mapper.xml
中配置使用二级缓存
1 | <cache |
- 在cache标签中,eviction属性用于配置缓存的回收策略
- LRU - 最近最少使用的,移除最长时间不被使用的对象。
- FIFO - 先进先出,按对象进入缓存的顺序来移除它们。
- SOFT - 软引用,基于垃圾回收器状态和软引用规则移除对象
- WEAK - 弱引用,更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认清除策略为 LRU
flushInterval
(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。- size(引用数目)属性可以被设置为任意正整数,要注意缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
readOnly
(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。type
用于指定缓存的实现类型, 默认是PERPETUAL
, 对应的是mybatis
本身的缓存实现类org.apache.ibatis.cache.impl.PerpetualCache
。
- 后续如果我们要实现自己的缓存或者使用第三方的缓存, 都需要更改此处。
- 我们的 POJO 需要实现序列化接口
3、示意图
2.4、自定义缓存并整合 ehCache
在实现 Cache 接口的自定义缓存类的 put 方法中,可以使其向
Redis
或者其他NoSQL
中存储数据,在自定义缓存类的getObject
方法中,让其从Redis
中取数据。
1、导入 ehCache
所需依赖
1 | <dependency> |
2、下载mybatis
和ehcache
的适配包
这里通过
Maven
方式引入
1 | <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> |
3、编写 ehCache.xml
配置文件
- 属性说明:
diskStore
:当内存中不够存储时,存储到指定数据在磁盘中的存储位置。- 必要属性
maxElementsInMemory
- 在内存中缓存的element的最大数目maxElementsOnDisk
- 在磁盘上缓存的element的最大数目,若是0表示无穷大- eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据
timeToIdleSeconds
,timeToLiveSeconds
判断overflowToDisk
- 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
- 可选属性
timeToIdleSeconds
- 当缓存在EhCache
中的数据前后两次访问的时间超过timeToIdleSeconds
的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大timeToLiveSeconds
- 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
1 |
|
4、在mapper.xml
中使用自定义缓存
1 |
|
5、其他Mapper使用该mapper的缓存
1 | <cache-ref namespace="com.hzx.mybatis.dao.EmployeeMapper"/> |
2.5、实体类和表中字段名不一致的解决方案
- 写SQL时起别名
- 在全局配置文件中开启驼峰命名规则
- 使用resultMap来自定义映射规则