SSM基础学习笔记

SSM框架:

1、界面层---servlet类---SpringMVC

2、业务逻辑层---service类---Spring

3、数据访问层(持久层)---dao类---MyBatis

  

一、MyBatis框架

MyBatis是JDBC与AOP动态代理相结合的一种SQL映射框架,通过实现SqlSession对象,执行SQL语句。

 

SQL映射文件的使用:

1、参数传入:

(1)、简单类型参数传入:

@Param("自定义参数名称")

 

(2)、引用类型参数传入:

 

2、自定义映射resultMap:

(1)、id:指定主键列的映射关系,

(2)、result:设置普通字段的映射关系

(3)、association:设置多对一的映射关系

(4)、collection:设置一对多的映射关系

 

3、动态SQL片段:

mybatis提供动态标签:

(1)、<if>:判断条件

(2)、<where>:用来包含多个<if>,即: <where> <if> <if>...</where>

(3)、<foreach>:对数组与集合遍历,foreach使用: List<Integer>

(4)、choose、when、otherwise(相当于于if...else if..else):选择条件

(5)、<trim>:用于去掉或添加标签前后内容

<trim 属性="关键字" >标签的常用属性:

prefix

在trim标签中的内容的前面添加某些内容

prefixOverrides

在trim标签中的内容的前面去掉某些内容

suffix

在trim标签中的内容的后面添加某些内容

suffixOverrides

在trim标签中的内容的后面去掉某些内容

 

 

Mybatis使用#{}与${}获取参数值的区别:

1、${}的本质就是字符串拼接,#{}的本质就是占位符赋值

2、${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;在SQL语句中不使用占位符,同时使用Statement进行编译,执行效率低,有sql注入的风险,缺乏安全性。

3、#{}使用占位符赋值的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号;在SQL语句中相当于使用?做占位符,同时使用PreparedStatement进行编译,执行效率高,能够避免sql注入,更安全。

 

Mybatis的一级缓存和二级缓存:

1、一级缓存是SqlSession级别的缓存。Mybatis默认开启一级缓存。

在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是它只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。

 

(1)、一级缓存失效的情况:

1)、不同的sqlSession,使用不同的一级缓存;只有在同一个sqlSession期间查询到的数据会保存在这个sqlSession的缓存中;

2)、同一个SqlSession但是查询条件不同;

3)、同一个SqlSession两次查询期间执行了任何一次增删改操作,增删改操作会把缓存清空;

4)、同一个SqlSession两次查询期间手动清空了缓存;

2、二级缓存是mapper级别的缓存,Mybatis默认是关闭二级缓存的。

多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

 

(1)、开启二级缓存需要注意的问题:

1)、对该表的操作与查询都在同一个namespace(命名空间)下,其他的namespace如果有操作,就会发生数据的脏读。

2)、对关联表的查询,关联的所有表的操作都必须在同一个namespace。

 

MyBatis缓存查询的顺序:

1、先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。

2、如果二级缓存没有命中,再查询一级缓存

3、如果一级缓存也没有命中,则查询数据库

4、SqlSession关闭之后,一级缓存中的数据会写入二级缓存

 

MyBatis的分页方式:

逻辑分页与物理分页

1、逻辑分页:使用MyBatis自带的RowBounds进行分页,是一次性查询很多数据,然后再在结果中检索分页的数据。这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。

2、物理分页:使用分页插件PageHelper或者自己写sql分页(limit),是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。

 

RowBounds分页方式是否一次性查询全部结果:

RowBounds表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为mybatis是对JDBC的封装,在JDBC驱动中有一个Fetch Size的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行next()的时候,去查询更多的数据。(有效防止内存溢出)

 

MyBatis的延时加载:

参考博客

MyBatis支持延时加载,延迟加载也称为懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。在真正使用数据的时候才发起查询,不用的时候不查询关联的数据,延迟加载又叫做按需查询。通过设置lazyLoadingEnabled=true即可开启延时加载。

 

MyBatis的执行器(Executor):

在应用层通过sqlSession执行的各类selectXXX和增删改操作在做了动态sql和参数相关的封装处理后,都被委托给具体的执行器去执行,包括一、二级缓存的管理,事务的具体管理,Statement和具体JDBC层面优化的实现等等。所以执行器比较像是sqlSession下的各个策略工厂实现,用户通过配置决定使用哪个策略工厂。

MyBatis提供了两种类型的执行器,缓存执行器(cacheEnabled)与非缓存执行器(BaseExecutor)

1、非缓存执行器

非缓存执行器分为三种,这三种类型的执行器都基于基础执行器(BaseExecutor)

BaseExecutor实现了大部分通用功能本地缓存管理、事务提交、回滚、超时设置、延迟加载等

(1)、简单执行器SimpleExecutor:

每执行一次update或select就开启一个Statement对象,用完立刻关闭Statement对象;

(2)、可重用执行器ReuseExecutor:

重复使用Statement对象。

(3)、批处理执行器BatchExecutor:

批量更新(update),且必要地方分开其中的select语句,确保动作易于理解

2、缓存执行器

缓存执行器(CachingExecutor)相对于其他执行器的差别在于,首先是在query()方法中判断是否使用二级缓存(也就是mapper级别的缓存)。虽然mybatis默认启用了CachingExecutor,但是如果在mapper层面没有明确设置二级缓存的话,就退化为SimpleExecutor。二级缓存的维护由TransactionalCache(事务化缓存)负责。

 

 

半自动ORM(对象/关系数据库)映射工具——MyBatis:

Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。

而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。

全自动与半自动的区别:

1、Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。

2、Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。

 

Mybatis常用插件:

1、MyBatisCodeHelperPro

2、Pagehelper分页插件

 

二、Spring框架:

代码参考:提取码:k34k

1、Spring是容器,用于创建与管理对象(解耦合)

2、核心技术:IOC(控制反转)与AOP(面向切面编程)

 

Spring的核心技术:

1、IOC(控制反转):

IOC是一种理论与思想,由容器代替开发人员完成对象的管理,IOC技术实现使用依赖注入(DI),底层是反射机制。

2、AOP(面向切面编程):

AOP是动态代理的规范化,在不修改源代码情况下进行功能增强,使用AOP要求在分析项目功能时,找出切面(@aspect),并合理安排切面的执行时间与执行位置。(运用切入点表达式)

 

IOC控制反转的实现方式:

1、基于XML的DI实现:

在Spring的配置文件中使用<bean>完成属性(set注入与构造注入)赋值。

2、基于注解的DI实现:

在Spring的类上使用注解(@Component),完成属性(@Value简单类型与@Autowired引用类型)赋值。

 

Spring支持bean的作用域:

Spring beans:即Spring容器所管理的Java 对象

Spring框架支持五种不同的作用域:

 

属性

详解

singleton

在Spring IOC容器中仅存在一个Bean实例,Bean以单实例的方式存在。

prototype

一个bean可以定义多个实例。

request

每次HTTP请求都会创建一个新的Bean。该作用域仅适用于WebApplicationContext环境。

session

一个HTTP Session定义一个Bean。该作用域仅适用于WebApplicationContext环境。

globalSession

同一个全局HTTP Session定义一个Bean。该作用域同样仅适用于WebApplicationContext环境

bean默认的scope属性是“singleton”。

 

 

BeanFactory和ApplicationContext的区别:

1、BeanFactory

BeanFactory是spring的原始接口,针对原始结构的实现类功能比较单一,BeanFactory接口实现的容器,特点是在每次获取对象时才会创建对象。

2、ApplicationContext

继承了BeanFactory接口,拥有BeanFactory的全部功能,并且扩展了很多高级特性,每次容器启动时就会创建所有的对象。

主要区别:

BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean 时才实例目标Bean;而ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean 。

 

 

Spring框架中bean的生命周期:

ApplicationContext容器中,Bean的生命周期流程如图所示,流程大致如下:

 

1、首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化,

2、按照Bean定义信息配置信息,注入所有的属性,

3、如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id,

4、如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory,

5、如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext,

6、如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation()方法,

7、如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法,

8、如果Bean配置了init-method方法,则会执行init-method配置的方法,

9、如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization()方法,

10、经过流程9之后,就可以正式使用该Bean了,对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该bean的实例,而对于scope为prototype的Bean,每次被调用都会new一个新的对象,期生命周期就交给调用方管理了,不再是Spring容器进行管理了

11、容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法,

12、如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此,整个Bean的生命周期结束。

 

Resource的查找与加载:

Resource接口是Spring资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成(每个实现类代表一种资源访问策略)。

Spring为Resource接口提供如下实现类:

1、UrlResource:访问网络资源的实现类。

2、ClassPathResource:访问类加载路径里资源的实现类。

3、FileSystemResource:访问文件系统里资源的实现类。

4、ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:

5、InputStreamResource:访问输入流资源的实现类。

6、ByteArrayResource:访问字节数组资源的实现类。 这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。

 

XML的自动装配机制:

根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

1、属性名称自动注入(byName):

Java类中引用类型的属性名和spring容器中(配置文件)<bean>的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。

 

2、属性类型自动注入(byType):

Java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性是同源关系的,这样的bean能够赋值给引用类型。

同源关系:

(1)、java类中引用类型的数据类型和bean的class的值是一样的。

(2)、java类中引用类型的数据类型和bean的class的值是父子类关系的。

(3)、java类中引用类型的数据类型和bean的class的值是接口和实现类关系的

 

 

Spring创建对象提供的注解:

1、@Component:创建对象;

2、@Repository:用于数据访问层即持久层,表示创建DAO对象,能访问数据库

3、@Service:用于业务逻辑层,表示创建Service对象,做业务、事务处理等

4、@Controller:用于界面层即控制层,表示创建控制器对象,接收请求,返回响应

注:@Repository,@Service,@Controller是给项目的对象分层的,都能够创建对象。

 

基于注解方式实现属性注入:

1、简单类型的DI注入

@Value("属性值")

2、引用类型的DI注入

(1)、默认使用的是byType自动注入:

@Autowired

(2)、使用byName方式:

@Autowired
@Qualifier(value="bean的id")  //限定词,用于指定注入bean
注:
对于采用@Qualifier("bean的id")注解,需要在多个实现类上分别加上各自的声明:@Service("bean的id")

(3)、默认是byName(先使用byName自动注入,如果byName赋值失败,再使用byType):

@Resource

3、@value使用的注意事项:

(以下问题都会造成,无法注入的问题)
(1)、不能作用于静态变量(static)
(2)、不能作用于常量(final)
(3)、不能在非注册的类中使用(类需要被注册在spring上下文中,如用@Service,@RestController,@Component等;
(4)、使用这个类时,只能通过依赖注入的方式,用new的方式是不会自动注入这些配置的。

 

AOP底层——动态代理:

1、JDK动态代理:

通过反射机制,实现reflect接口(有接口时使用)

参考博客

具体实现步骤:

(1)、通过实现 InvocationHandler 接口创建自己的调用处理器;

(2)、通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;

(3)、通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

(4)、通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

2、CGLIB动态代理:

通过继承第三方的工具库(无接口时使用)

 

AOP功能通知(增强):

1、前置通知@Before:在一个方法之前执行的通知

2、后置通知@AfterReturning:在某连接点正常完成后执行的通知。

3、环绕通知@Around:在方法调用前后触发的通知。

4、异常通知@AfterThrowing:在方法抛出异常退出时执行的通知。

5、最终通知@After:当某连接点退出的时候执行的通知(无论是否正常退出)

 

Spring的声明式事务管理处理方案:

Spring事务是实现方式:编程式事务管理与声明式事务管理

事务要求同时成功,同时失败(提交事务commit,回滚事务rollback)

基于声明式事务管理的处理方案:

1、注解方案(小项目):

Spring框架中使用AOP的环绕机制,利用@Transactional注解增加事务功能。

2、XML配置文件方案(大项目):

使用aspectj框架功能,在Spring配置文件声明事务(管理器对象与类型),实现业务与事务完全分离。

 

@Transactional实现原理

1、事务开始时,通过AOP机制,生成一个代理connection对象,并将其放入DataSource实例的某个与DataSourceTransactionManager相关的某处容器中。在接下来的整个事务中,客户代码都应该使用该connection连接数据库,执行所有数据库命令。

(不使用该connection连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚)

2、事务结束时,回滚在第一步骤中得到的代理connection对象上执行的数据库命令,然后关闭该代理connection对象。

(事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)

 

@Transactional(属性)详解:

 

1、Isolation类的事务隔离级别详解:

@Transactional(isolation = Isolation.READ_UNCOMMITTED)

读取未提交数据

@Transactional(isolation = Isolation.READ_COMMITTED)

读取已提交数据

@Transactional(isolation = Isolation.REPEATABLE_READ)

可重复读

@Transactional(isolation = Isolation.SERIALIZABLE)

串行化读

2、Propagation类的事务传播行为详解:

@Transactional(propagation= Propagation.传播属性)

传播属性

描述

REQUIRED

支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行。

MANDATORY

支持当前事务,如果当前没有事务,就抛出异常。

REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。

NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

NEVER

以非事务方式执行,如果当前存在事务,则抛出异常。

NESTED

支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

 

Spring5新功能:

1、整合日志框架

2、@Nullable注解

3、函数式注册对象

4、整合JUnit5单元测试框架

5、SpringWebflux编程模型的使用:注解式与函数式

 

三、SpringMVC框架

SpringMVC是容器,基于原生的Servlet,用于界面层,通过前端控制器(DispatcherServlet),对请求和响应进行统一处理。

 

SpringMVC注解式开发:

1、创建控制器对象:

@Controller

用于界面层,表示创建控制器对象,接收请求,返回响应

 

2、建立请求映射关系:

@RequestMapping

将请求和处理请求的控制器方法关联起来,建立映射关系。(相关参考

(1)、@RequestMapping属性:

 

属性

解释

备注

value/path

通过请求的请求地址匹配请求映射

属性为字符串类型的数组,且必须设置

method

通过请求的请求方式(GET、PUT、POST、DELETE 、PATCH)匹配请求映射

属性为RequestMethod类型的数组:

例:RequestMethod.GET等

produces

指定返回的内容类型

了解

consumes

指定处理请求的提交内容类型

了解

header

通过请求的请求头信息匹配请求映射

根据header请求头信息去过滤请求映射所匹配的请求

(了解)

params

通过请求的请求参数匹配请求映射

根据param请求参数信息去过滤请求映射所匹配的请求

(了解)

(2)、@RequestMapping派生注解:

用于处理指定请求方式的控制器方法

注解

解释

@GetMapping

处理get请求的映射,通常对应查询操作(select)

@PostMapping

处理post请求的映射,通常对应新增操作(insert)

@PutMapping

处理put请求的映射(更新整体),通常对应修改操作(update)

@DeleteMapping

处理delete请求的映射,通常对应删除操作(drop)

@PatchMapping

Patch方式是put方式的一种补充(更新局部)

3、获取请求参数

@RequestParam

将请求参数和控制器方法的形参创建映射关系

(1)、@RequestParam属性

 

属性

备注

value

指定为形参赋值的请求参数的参数名

required

设置是否必须传输此请求参数,默认值为true,若设置为false,没有传输时注解所标识的形参的值为null

defaultValue

不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值 为""时,则使用默认值为形参赋值

(2)、@RequestParam相同用法的注解:

注解

解释

备注

@RequestHeader

将请求头信息和控制器方法的形参创建映射关系

三个属性:value、required、defaultValue

@CookieValue

cookie数据和控制器方法的形参创建映射关系

三个属性:value、required、defaultValue

4、报文信息转换:

(1)、将请求报文转换为Java对象

1)、@RequestBody注解:

获取请求体

 

2)、RequestEntity类:

封装请求报文的类,通过getHeaders()获取请求头信息,通过getBody()获取请求体信息

 

(2)、将Java对象转换为响应报文

1)、@ResponseBody注解

将java对象转为Json格式的响应数据

//可采用:
@RestController = @Controller + @ResponseBody

 

2)、ResponseEntity类

返回值就是响应到浏览器的响应报文

 

5、集中异常处理机制:

//将当前类标识为异常处理的组件
@ControllerAdvice
//用于设置所标识方法处理的异常
@ExceptionHandler

 

 

过滤器与拦截器的区别

1、创建方式不同:

(1)、过滤器是servlet中tomcat服务器创建的对象,

(2)、拦截器是框架中SpringMVC容器中创建的对象

2、实现方式不同:

(1)、过滤器实现Filter接口对象,

(2)、拦截器实现HandleInterceptor接口对象

3、执行时间不同:

(1)、过滤器是一个执行时间点(请求处理前)

(2)、拦截器有三个执行时间点(请求处理前preHandle(),控制器方法执行后postHandle(),请求处理完成后afterCompletion())

 

多个拦截器的执行顺序:

preHandle()返回值为boolean类型:

返回true表示放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法

1、若每个拦截器的preHandle()都返回true

此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关: preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行

2、若某个拦截器的preHandle()返回了false

preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false 的拦截器之前的拦截器的afterComplation()会执行;

 

SpringMVC执行流程:

1、浏览器提交请求到中央调度器

2、中央调度器(也叫前端控制器)直接将请求转给处理器映射器。

3、处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后返回给中央调度器。

4、中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。

5、处理器适配器调用执行处理器。

6、处理器将处理结果及要跳转的视图封装到一个对象ModelAndView中,并将其返回给处理器适配器。

7、处理器适配器直接将结果返回给中央调度器。

8、中央调度器调用视图解析器,将ModelAndView中的视图名称封装为视图对象。

9、视图解析器将封装了的视图对象返回给中央调度器

10、中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。

11、中央调度器响应浏览器。

 

 

posted on 2022-03-10 10:01  爱文(Iven)  阅读(227)  评论(0编辑  收藏  举报

导航