目录
Spring
轻量:从大小到开销都是轻量的
IOC
控制反转IOC:引入了“第三方”——IOC容器,使原有对象之间没有了耦合关系,全部对象的控制权都上缴给第三方,所以IOC容器成为整个系统的关键核心,它起到了一种类似“粘合剂”的作用。此时,如果对象A运行时需要获取对象B,不再像原来一样主动创建对象B或者使用已经创建的对象B,而是IOC主动创建一个容器注入到对象A需要的地方,A的控制权因此“反转”了。
AOP
面向切面编程AOP:是面向对象编程OOP的补充和完善。OOP引入封装、继承和多态来建立一种对象层次结构,允许定义从上到下的关系,但并不适合定义从左到右的关系。而AOP利用“横切”的技术,将影响了多个类的公共行为封装到一个可重用模块,这些“Aspect”就是与业务无关,却为业务模块所共同调用的逻辑。这种方式有助于减少系统的重复代码,降低模块间的耦合度,有利于未来的可操作性和可维护性。
常用的注入方式
注解注入(@Autowired)
配置文件配置bean注入
spring支持的bean作用域
- singleton(默认):单例模式,在整个Spring IOC容器中,使用singleton定义的bean将只有一个实例
- protptype(创建销毁代价大):原型模式,每次获取prototype定义的bean时都会产生一个新的bean实例
- request:对于每次http请求,都产生新实例
- session:对于每次httpsession,都产生一个新实例
- globalsession:每个全局的httpsession,都将产生一个新实例
spring事务实现方式
- 编程式事务管理。在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法。
- 基于TransactionProxyFactoryBean的声明式事务管理
- 基于 @Transactional 的声明式事务管理
- 基于Aspectj AOP配置事务
spring的事务隔离
- 未提交读(read uncommitted)允许脏读,但不允许更新丢失,如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可通过“排他写锁”实现。
- 提交读(read committed)允许不可重复读,不允许脏读。可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
- 可重复读(repeatable read)禁止不可重复读取和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
- 序列化(serializable)提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
Spring中提供一个标识:isolation_default。表示使用后端数据库默认的隔离级别。大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。MySQL的默认隔离级别是Repeatable read。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。
- 脏读:一个事务读到另一个事务未提交的更新数据
- 不可重复读:一个事务先后读取同一数据时,由于被另一个事务修改而产生读取错误
- 幻读:两个事务同时修改数据,导致读取时出现错误,好像产生了幻觉
处理请求的流程
Spring MVC
核心组件
- DispatcherServlet:中央控制器,把请求给转发到具体的控制类
- Controller:具体处理请求的控制器
- HandlerMapping:映射处理器,负责映射中央处理器转发给controller时的映射策略
- ModelAndView:服务层返回的数据和视图层的封装类
- ViewResolver:视图解析器,解析具体的视图
- Interceptors:拦截器,负责拦截我们定义的请求然后做处理工作
运行流程
- 用户向服务器发送请求,请求被spring前端控制 DispatcherServlet捕获
- DispatcherServlet对请求URL进行解析,得到请求资源标识符URI,根据该URI调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器)
- DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter
- 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。
- Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象
- 根据返回的ModelAndView,选择一个适合的ViewResolver返回给DispatcherServlet
- ViewResolver结合Model和View来渲染视图
- 将渲染结果返回给客户端
@RequestMapping
作用:可用于类或方法上,处理请求地址映射。用于类上时,表示类中所有相应请求的方法都是以该地址作为父路径
六个属性:
- value:指定请求的实际地址
- method:指定请求的类型,get、post、put、delete等
- consumes:指定处理请求的提交内容类型,application/json、text/html等
- produces:仅当request请求头中的accept类型中包含该指定类型才返回
- params:指定request中必须包含某些参数值时,才让该方法处理
- headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
Mybatis
#{}和${}的区别
- #{}是编译预处理,${}是字符串替换
- Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值。得到的值会加上双引号""
- 在处理 ${}时,就是把 ${}替换成变量的值,不加上双引号
- #{}可以有效防止sql注入,提高系统安全性
分页方式
- 数组分页
- sql分页
- 拦截器分页
- RowBounds分页
逻辑分页和物理分页:、
- 逻辑分页是一次性查找后进行分页。物理分页在sql语句中使用limit,每次查询分页结果
- 物理分页速度上不一定快于逻辑分页,逻辑分页速度上也不一定快于物理分页。
- 物理分页总是优于逻辑分页,没有必要将属于数据库的压力施加到应用端
延迟加载
延迟加载(懒加载):加载对象的同时不加载其关联的对象,在需要使用数据的时候,才真正加载
Mybatis是否支持延迟加载?
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载:lazyLoadingEnabled=true|false
延迟加载的原理:
使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法。比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。
CGLIB(Code Generator Library)是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。
一级缓存和二级缓存
一级缓存(默认):基于PerpetualCache(Mybatis的一个缓存类)的HashMap本地缓存,其存储作用域为session,当session flush或close以后,该session中所有的Cache就将清空。
二级缓存:与一级缓存机制相同,也是采用PerpetualCache、HashMap存储,不同在于其存储作用域为Mapper,并且可自定义存储源,如Ehcache。要开启二级缓存,需要实现Serializable序列化接口(可用来保存对象的状态),可在他的映射文件中配置<cache/>
。
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储。
缓存数据更新机制,当一个作用域(一级缓存Session/二级缓存Namespaces)进行了C/U/D操作后,默认该作用域下所有select中的缓存将被clear。