框架相关

1.springMVC

1.1 工作原理

  1. 用户发送请求至前端控制器DispatcherServlet

  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。

  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器

  5. 执行处理器(Controller,也叫后端控制器)。

  6. Controller执行完成返回ModelAndView

  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet

  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器

  9. ViewReslover解析后返回具体View

  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。

  11. DispatcherServlet响应用户

1.2 常用的SpringMVC注解

@RequestMapping 用于请求url映射

@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象

@ResponseBody注解实现将controller方法返回对象转化为json响应给客户

1.3 SpringMVC和Struts2的区别

相同点

都是表现层框架,都基于MVC编写

底层都是ServletAPI

处理请求都是一个核心控制器

不同点

SpringMVC入口是一个前端控制器,而Struts2是一个filter过滤器

SpringMVC是基于方法开发,而Struts2是基于类开发

SpringMVC目前没有发现漏洞,Struts2有漏洞

其他对比

  1. Struts2 是类级别的拦截, 一个类对应一个 request 上下文, SpringMVC 是方法级别的拦截,一个方法对应 一个request 上下文,而方法同时又跟一个 url 对应,所以说从架构本身上 SpringMVC 就容易实现 restful url,而 struts2 的架构实现起来要费劲,因为 Struts2 中 Action 的一个方法可以对应一个 url,而其类属性却被所有方法共享,这也 就无法用注解或其他方式标识其所属方法了。

    2.由上边原因, SpringMVC 的方法之间基本上独立的,独享 request response 数据,请求数据通过参数获取, 处理结果通过 ModelMap 交回给框架,方法之间不共享变量,而 Struts2 搞的就比较乱,虽然方法之间也是独立的, 但其所有 Action 变量是共享的,这不会影响程序运行,却给我们编码 读程序时带来麻烦,每次来了请求就创建一个 Action,一个 Action 对象对应一个 request 上下文。

    ​3.由于 Struts2 需要针对每个 request 进行封装,把 request, session 等 servlet 生命周期的变量封装成一个一个 Map,供给每个 Action 使用,并保证线程安全,所以在原则上,是比较耗费内存的

    ​4. 拦截器实现机制上, Struts2 有以自己的 interceptor 机制, SpringMVC 用的是独立的 AOP 方式,这样导致 Struts2 的配置文件量还是比 SpringMVC 大

    ​5.SpringMVC 的入口是 servlet,而 Struts2 是 filter(这里要指出, filter 和 servlet 是不同的。),这就导致了二者的机制不同,这里就牵涉到 servlet 和 filter 的区别了。

    ​6.SpringMVC 集成了 Ajax,使用非常方便,只需一个注解@ResponseBody 就可以实现,然后直接返回响应文 本即可,而 Struts2 拦截器集成了 Ajax,在 Action 中处理时一般必须安装插件或者自己写代码集成进去,使用起来也 相对不方便。

    ​7.SpringMVC 验证支持 JSR303,处理起来相对更加灵活方便,而 Struts2 验证比较繁琐,感觉太烦乱。

    8.Spring MVC 和 Spring 是无缝的。从这个项目的管理和安全上也比 Struts2 高(当然 Struts2 也可以通过不 同的目录结构和相关配置做到 SpringMVC 一样的效果,但是需要 xml 配置的地方不少)。

    ​9.设计思想上, Struts2 更加符合 OOP 的编程思想, SpringMVC 就比较谨慎,在 servlet 上扩展。

    ​10.SpringMVC 开发效率和性能高于 Struts2

    ​11.SpringMVC 可以认为已经 100%零配置

1.4 什么是MVC

MVC

MVC模式的概念

1.Model(业务模型):应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据,说白了就是确定要打的地基等一系列信息的。

2.view(视图):应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。其实就是反映了盖出来的到底是楼还是房。

3.controller(控制器):应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

其实就是决定收集到到底是开发商要来盖楼盘还是个体户要来盖房子。

2.Spring

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

2.1使用Spring的原因,Spring的优点有什么

2.1.1IOC容器

控制反转,一种设计思想,是将设计好的对象交给容器管理,在传统的方式中,直接在对象内通过new对象来创建对象,而IOC是专门有一个容器来创建这些对象,由Ioc容器来控制对象的创建

传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活

正转,在传统项目中,我们在对象中主动去控制和获取依赖对象

反转,由容器来帮忙创建及注入依赖对象,依赖对象的获取反转了

简单来说:创建对象的权利,交给spring容器创建

2.1.1.1DI依赖注入

依赖注入和IOC其实是一样的,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”

Spring提供多种依赖注入的方法

1.Set 注入

2.构造器注入

3.静态工厂的方法注入

4.实例工厂的方法注入

简单的说:如果一个对象A需要使用另一个对象B才能实现某个功能,这时就可以说A对象依赖于B对象,而Spring容器在创建A对象时,会自动将A对象需要的B对象注入到A对象中,此过程就是依赖注入

2.1.2AOP

面向切面编程,是面向对象编程(OOP)的补充和完善,OOP会造成大量重复代码,是纵向的,而AOP是横向的,面向切面的,可以解剖开封装对象的内部,将与业务无关的封装到一个可重用的模块,命名为Aspect,这样就可以减少重复代码,降低耦合度。

OOP 允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在 OOP 设计中,它导致了大量代码的重复,而不利于各个模块的重用。除了日志功能,还有事务,权限等。

Aspect (切面) :通常是一个类,里面可以定义切入点和通知

JointPoint (连接点) :程序执行过程中明确的点,一般是方法的调用

Advice (通知) :AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

简单的说:面向切面编程,将跟业务逻辑没有关系的代码提取出来,在调用目标方法之前或者之后执行。常用的场景,事务,日志,权限控制,异常处理等方面

2.1.3MVC

SpringMVC的介绍在上面

2.1.4Spring事务管理

声明式事务管理和编程式事务管理

1.编程式事务是自己写事务处理的类,然后调用

2.声明式事务是在配置文件中配置,一般搭配在框架里面使用

spring事务的本质是数据库对事务的支持

2.1.4.1事务的性质

2.1.4.1.1 事务的四大属性

原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。

一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。

隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

2.1.4.1.2 事务的并发问题

脏读:脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的

不可重复读:不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新,不可重复读的重点是修改

幻读:幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,幻读的重点在于新增或者删除

2.1.4.1.3 Mysql事物的隔离级别

读未提交,不可重复读,可重复读,串行化,默认是可重复读

2.1.4.1.4 基本事务属性

事务管理器接口PlatformTransactionManager通过getTransaction来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性

有五个,传播行为,隔离级别,只读,事务超时,回滚规则

传播行为:事务的第一个方面是传播行为(propagation behavior)。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播

隔离级别:隔离级别定义了一个事务可能受其他并发事务影响的程度,比如脏读,不可重复读,幻读

只读:如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施

事务超时:为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束

回滚规则:这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常

事务分为全局事务局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogic、WildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。

2.1.4.2 Spring事务

2.1.4.2.1 声明式事务和编程式事务

Spring提供了对编程式事务和声明式事务的支持,编程式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于用户将操作与事务规则进行解耦

简单地说,编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现

声明式事务管理也有两种常用的方式,一种是基于tx和AOP名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽

一般选择声明式事务,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务

2.1.4.2.2 @Transactional实现事务管理

使用@Transactional注意点:

如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口;

建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制(基于接口的代理)是没问题;
而使用使用CGLIB代理(继承)机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”;

2.1.4.2.3 Spring事务的五大隔离级别

1.ISOLATION_DEFAULT:用底层数据库的默认隔离级别,数据库管理员设置什么就是什么

2.ISOLATION_READ_UNCOMMITTED(未提交读):最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)

3.ISOLATION_READ_COMMITTED(提交读):一个事务提交后才能被其他事务读取到(该隔离级别禁止其他事务读取到未提交事务的数据、所以还是会造成幻读、不可重复读)、sql server默认级别

4.ISOLATION_REPEATABLE_READ(可重复读):可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(该隔离基本可防止脏读,不可重复读(重点在修改),但会出现幻读(重点在增加与删除))(MySql默认级别,更改可通过set transaction isolation level 级别)

5.ISOLATION_SERIALIZABLE(序列化):代价最高最可靠的隔离级别(该隔离级别能防止脏读、不可重复读、幻读)

丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的;

幻读:同样的事务操作过程中,不同时间段多次(不同事务)读取同一数据,读取到的内容不一致(一般是行数变多或变少)。

脏读:一个事务读取到另外一个未提及事务的内容,即为脏读。

不可重复读:同一事务中,多次读取内容不一致(一般行数不变,而内容变了)。

2.2 Spring IoC容器配置Bean的方式

基于XML文件进行配置

基于注解进行配置

基于Java程序进行配置(Spring 3+)

2.3 依赖注入时注入集合属性

在定义Bean属性时,通过 / / / 分别为其注入列表、集合、映射和键值都是字符串的映射属性

2.4 Spring使用注解来配置Bean

可以用@Component、@Controller、@Service、@Repository注解来标注需要由Spring IoC容器进行对象托管的类。这几个注解没有本质区别,只不过@Controller通常用于控制器,@Service通常用于业务逻辑类,@Repository通常用于仓储类(例如我们的DAO实现类),普通的类用@Component来标注

1.@Component spring通用注解

2.@Controller 对应表现层的Bean,也就是Action

3.@Service 对应的是业务层Bean

4.@Repository 对应数据访问层Bean

5.@Resource 默认按名称装配,当找不到名称匹配的bean再按类型装配.

6.@Autowired 默认按类型匹配,自动装配(Srping提供的),可以写在成员属性

2.5 Spring容器的7个模块

Spring

Spring核心容器类:提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,她是工厂模式的实现。BeanFactory使用控制反转(Ioc)模式将应用程序的配置和依赖性规范与实际的应用代码程序分开

SpringAOP:通过配置管理特性,Spring AOP模块直接面向切面的编程功能集成到了Spring框架中,所以可以很容易的使Spring框架管理的任何对象支持 AOP。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用Spring AOP,不用依赖于EJB组件,就可以将声明性事务管理集成到应用程序中

SpringORM:Spring框架集成了若干ORM框架,从而提供了ORM的对象关系工具,其中包括 JDO、Hibernate、iBatis和TopLink。所有这些都遵从Spring的通用事务和DAO异常层结构(ORM(object relation mapping) 对象关系映射关系 ,面向对象的对象模型和关系型数据之间的相互转换。基于关系型数据库的数据存储,实现一个虚拟的面向对象的数据访问接口。理想状态下,基于一个这样一个面向对象的接口,持久化一个oo对象应该不需要了解任何关系型数据库存储的数据实现细节 )

SpringDao:JDBC DAO抽象层提供了有意义的异常层次的结构,可用该结构来管理异常处理和不同数据供应商抛出的异常错误信息。异常层次结构简化了错误处理,并且大大的降低 了需要编写的异常代码数量(例如,打开和关系连接)。Spring DAO的面向JDBC的异常遵从通用的DAO异常层结构

SpringWeb:Web上下文模块建立在上下文模块(Context)的基础之上,为基于Web服务的应用程序提供了上下文的服务。所以Spring框架支持 Jakarta Struts的集成。Web模块还简化了处理多部分请求及将请求参数绑定到域对象的工作

SpringContext:Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化校验和调度功能

SpringMVC:Spring的MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的,MVC容纳的大量视图技术,包括JSP、Velocity、Tiles、iText和Pol

2.6 Spring的核心类

BeanFactory:产生一个新的实例,可以实现单例模式

BeanWrapper:提供统一的get及set方法

ApplicationContext:提供框架的实现,包括BeanFactory的所有功能

2.7 SpringJDBC和传统JDBC的区别

SpringJDBC不管连接,不管事务,不管异常,不管关闭

2.8 Spring的注入方式

接口注入

setter方法注入

构造方法注入

spring4可以注解注入@Autowired

2.9 Spring循环注入

A有一个构造器里面的参数是类B,然后类B里面有个构造器参数是类C,类C里面有个构造器参数是类A,就是我们会发现其实引用循环了A 里面有B的引用,B里面有C的引用,C里面又有A的引用

循环依赖又分为构造器循环依赖和set循环依赖

2.10 BeanFactory和ApplicationContext

BeanFacotry是spring中比较原始的Factory ,原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等

ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:

MessageSource, 提供国际化的消息访问

资源访问,如URL和文件

事件传播

载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

2.11 BeanFactory和ApplicationContext的区别

相同点:

(1)applicationContext与beanFactory都是接口,applicationContext是beanFactory的子接口

(2)都是使用xml configuration

(3) beanFactory提供了基本的ioc和di, applicationContext提供了高级一点的特性。

不同点:

(1)BeanFactory不支持i18n,applicationContext支持

(2)常用的BeanFactory的子类是XMLBeanFactory,applicationContext的常用子类是ClassPathXmlApplicationContext,在企业级应用中使用继承了applicationContext的 WebApplicationContext ,

(3)简单的测试可以使用BeanFactory。(资源消耗比较少)

(4)使用beanFactory延迟加载的方式实例化bean

2.12 Spring的通知有哪些

前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)

返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回

抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知

后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)

环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行

环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知

2.13 Spring如何处理线程并发

Spring中使用ThreadLocal解决线程安全问题

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大

而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal

由于ThreadLocal中可以持有任何类型的对象,低版本JDK所提供的get()返回的是Object对象,需要强制类型转换。但JDK5.0通过泛型很好的解决了这个问题,在一定程度地简化ThreadLocal的使用

概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响

2.14 注解开发和xml配置

xml开发

优点:

1.XML配置方式进一步降低了耦合,使得应用更加容易扩展,即使对配置文件进一步修改也不需要工程进行修改和重新编译

2.在处理大的业务量的时候,用XML配置应该更加好一些。因为XML**更加清晰的表明了各个对象之间的关系**,各个业务类之间的调用。同时spring的相关配置也能一目了然。 当然,有人会说,用XML配置,在大的业务量时候会使得XML文件过大,不容易查看。这一点我们完全可以利用业务分解书写多个XML配置文件就可以了

缺点:

配置文件读取和解析需要花费一定的时间,配置文件过多的时候难以管理,无法对配置的正确性进行校验,增加了测试难度

注解开发

优点:

1.在class文件中,可以降低维护成本,annotation的配置机制很明显简单

2.不需要第三方的解析工具,利用java反射技术就可以完成任务

3.编辑期可以验证正确性

4.提高开发效率

缺点:

1.如果需要对于annotation进行修改,那么要重新编译整个工程

2.业务类之间的关系不如XML配置那样容易把握

3.如果在程序中annotation比较多,直接影响代码质量,对于代码的简洁度有一定的影响

基于注解,项目开发要快一些,不用去编写各种xml文件,但是长远维护方面,还是xml更好一点

用一句话来概括就是:写起来比较简单、方便,看起来也直观,但是不方便修改

而基于xml配置的方式:写起来比较灵活,修改比较方便,但是写起来很烦琐


3.Mybatis

3.1 什么是SQL注入

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令

3.2 JDBC有什么不足,Mybatis是如何解决的

1.数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题

解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接

2.Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码

解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离

3.向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应

解决:Mybatis自动将java对象映射至sql语句

4.对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便

解决:Mybatis自动将sql执行结果映射至java对象

3.3 Mybatis的工作流程

Mybatis

1.Mybatis配置

SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息

mapper.xml,即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载

2.通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

3.由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession(DefaultSqlSession)进行

4.mybatis底层自定义了Executor(BaseExecutor)执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器

5.Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等,mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id

6.Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过 Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数

7.Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过 Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程

3.4 Mybatis的介绍

Mybatis是一个优秀的ORM框架.应用在持久层. 它对jdbc的操作数据库过程进行封装,使开发者只需要关注 SQL本身,而不需要花费精力去处理例如注册驱动创建connection、等jdbc繁杂的过程代码.一般使用mapper代理的方式开发.直接在xml里面写sql(如果对hibernate了解.可以话题转向mybatis和hibernate的对比)

3.5 Mybatis编程步骤

1.创建SqlSessionFactory

2.通过SqlSessionFactory创建SqlSession

3.通过sqlsession执行数据库操作

4.调用session.commit()提交事务

5.调用session.close()关闭会话

3.6 sqlSession/Factory/Builder

sqlSession封装了对数据增删改查的方法

sqlSession是通过sqlSessionFactory创建的

sqlSessionFactory是通过sqlSessionFactoryBuild创建的

sqlSessionFactoryBuild是创建sqlSessionFactory时使用的.一旦创建成功后就不需要

sqlSessionFactory是一个接口, 类里重载了opensession的不同的方法使用范围是在整个运行范围内,一旦创建可以重复使用.可以当做单实例对象来管理

sqlSession是面向用户的一个操作数据库的接口 每个线程都应该有自己的sqlSession并且sqlSession不可以共享. 线程是不安全的,打开一个sqlSession用完之后就要关闭

3.7 Mybatis一级缓存和二级缓存

MyBatis的一级查询缓存是由org.apache.ibatis.cache.impl.PerpetualCache类的HashMap本地缓存实现的,它的作用域是SqlSession,它的作用域也是生命周期,假如同一个SqlSession中执行两次sql语句的查询,这两次的查询的位置是不同的,第一次查询时,由于没有缓存结果则是从数据库中进行查询结果,得到结果后写入缓存并将结果返回给查询语句,而在进行第二次查询时,这时缓存中已经有符合条件的结果集,这次的查询就会在缓存获得结果并返回,而不会向数据库进行查询。当SqlSession结束后相应的缓存也就销毁了

ps:myBatis默认一级查询时开启状态,而且不能关闭

二级缓存与一级缓存不同在于它更强大一些,强大在它的生命周期比一级缓存长二级缓存的生命周期是与整个应用同步的,与应用同生共死,这个时候二级缓存就与SqlSession没有关系了。这是从它们两者的生命周期上来讲,除此之外它俩的用途目的也不一样,一级缓存是用来共享数据提升速度和效率的,而二级缓存则是为了延长查询结果的保存时间,从而提高系统性能而已,二级缓存也是可以用于共享数据的

Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句,value为从查询出来映射生成的java对象,Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。二级缓存是可以跨SqlSession的

3.8 MyBatis中使用#和$书写占位符

#将传入的数据都当成一个字符串,会对传入的数据自动加上引号 

$将传入的数据直接显示生成在SQL中

注意:使用$占位符可能会导致SQL注射攻击,能用#的地方就不要使用$,

写order by子句的时候应该用$而不是#

3.9 Mybatis中命名空间(namespace)

在大型项目中,可能存在大量的SQL语句,这时候为每个SQL语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在MyBatis中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个SQL语句就成了定义在这个命名空间中的一个ID。只要我们能够保证每个命名空间中这个ID是唯一的,即使在不同映射文件中的语句ID相同,也不会再产生冲突了


3.10 动态Sql

对于一些复杂的查询,我们可能会指定多个查询条件,但是这些条件可能存在也可能不存在,例如在58同城上面找房子,我们可能会指定面积、楼层和所在位置来查找房源,也可能会指定面积、价格、户型和所在位置来查找房源,此时就需要根据用户指定的条件动态生成SQL语句。如果不使用持久层框架我们可能需要自己拼装SQL语句,还好MyBatis提供了动态SQL的功能来解决这个问题。MyBatis中用于实现动态SQL的元素主要有:

1.if 2.choose / when / otherwise 3.trim 4.where 5.set 6.foreach


4.Hibernate

4.1 Hibernate的开发流程

1.加载配置文件,读取配置文件的参数
2.创建SessionFactory,内部有连接池
3.打开 session 获取连接,构造 session 对象
4.开启事务
5.操作
6.提交事务
7.关闭Session
8.关闭连接池

4.2 Hibernate中对象的三种状态

瞬时态 不存在持久化标识OID,尚未与Hibernate Session关联对象,被认为处于瞬时态,失去引用将被JVM 回收
持久态 存在持久化标识 OID,与当前 session 有关联,并且相关联的 session 没有关闭 , 并且事务未提交
托管态 存在持久化标识 OID,但没有与当前 session 关联,脱管状态 改变 hibernate 不能检测到

4.3 hibernate 的缓存机制

一级缓存(Session缓存)

属于事务级数据缓冲,一旦数据结束,缓存随即失效,一个 Session 的生命周期对应一个数据库事务或一个程序事务,总是被打开并且不能被关闭,保证一个Session中两次请求同一个对象时,取得的是同一个java实例,可以避免数据冲突

在对于同一个对象进行循环引用时,不至于产生堆栈溢出

当数据库事务结束时,对于同一数据表行,不会产生数据冲突。因为对于数据库中的一行,最多有一个对象来表示它

一个事务中可能会有很多个处理单元,在每一个处理单元中做的操作都会立即被其他的数据单元得知

二级缓存(SessionFactory缓存)

所有的 Session 共享同一个二级缓存。在二级缓存中保存持久化实例的散装形式的数据,持久化不同的数据需要不同的 Cache 策略,设置 Hibernate 二级缓存需要分两步:首先,确认使用什么数据并发策略。然后,配置缓存过期时间并设置 Cache提供器

4.4 查询方式

HQL,QBC,SQL

4.5 Hibernate和Mybatis的区别

相同点

都是通过SessionFactoryBuilder由xml文件生成SessionFactory,然后由SessionFactory生成Session,由Session来执行事务和SQL语句
都支持JDBC事务操作

Mybatis优势

MyBatis 可以进行更为细致的 SQL 优化,可以减少查询字段。
MyBatis 容易掌握,而 Hibernate 门槛较高。

Hibernate 优势

Hibernate 的 DAO 层开发比 MyBatis 简单, Mybatis 需要维护 SQL 和结果映射。
Hibernate 对对象的维护和缓存要比 MyBatis 好,对增删改查的对象的维护要方便。
Hibernate 数据库移植性很好, MyBatis 的数据库移植性不好,不同的数据库需要写不同 SQL。
Hibernate 有更好的二级缓存机制,可以使用第三方缓存。 MyBatis 本身提供的缓存机制不佳。

4.6 Hibernate 和 JDBC

相同点

两者都是 java 数据库操作的中间件
两者对数据库进行直接操作的对象都是线程不安全的,都需要及时关闭。
两者都可对数据库的更新操作进行显式的事务处理。

不同点

JDBC 是 SUN 公司提供一套操作数据库的规范,使用 java 代码操作数据库
Hibernate 是一个基于 jdbc 的主流持久化框架,对 JDBC 访问数据库的代码做了封装
SQL语句不同,一个是标准SQL,一个是HQL

操作对象不同
JDBC操作的是数据,将数据通过SQL语句直接传送到数据库
Hibernate操作的是持久化框架,由底层持久化对象的数据更新到数据库

数据状态不同
JDBC 操作的数据是“瞬时”的,变量的值无法与数据库中的值保持一致
Hibernate 操作的数据是可持久的,即持久化对象的数据属性的值是可以跟数据库中的值保持一致的

4.7 get 和 load 的区别

get 是立即加载, load 是延时加载

get 会先查一级缓存,再查二级缓存,然后查数据库;load 会先查一级缓存,如果没有找到,就创建代理对象,等需要的时候去查询二级缓存和数据库

get 如果没有找到会返回null, load如果没有找到会抛出异常

当我们使用 session.load()方法来加载一个对象时,此时并不会发出 sql 语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的 id 值,只有当我们要使用这个对象,得到其它属性时,这个时候才会发出 sql 语句,从数据库中去查询我们的对象;相对于 load 的延迟加载方式, get 就直接的多,当我们使用session.get()方法来得到一个对象时,不管我们使不使用这个对象,此时都会发出 sql 语句去从数据库中查询出来

4.8 Hibernate 的优化

数据库设计调整。

HQL 优化。

API 的正确使用(如根据不同的业务类型选用不同的集合及查询 API)。

主配置参数(日志,查询缓存, fetch_size, batch_size 等)。

映射文件优化(ID 生成策略,二级缓存,延迟加载,关联优化)。

一级缓存的管理。

针对二级缓存,还有许多特有的策略。

事务控制策略

制定合理的缓存策略

4.9 Hibernate延迟加载

为了避免一些无谓的性能开销,在真正需要用数据的时候,才执行数据加载操作

4.10 Hibernate三种检索方式

立即检索
优点
对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象
缺点
1.select 语句太多
2.可能会加载应用程序不需要访问的对象白白浪费许多内存空间
延迟检索
优点
由应用程序决定需要加载哪些对象,可以避免可执行多余的 select 语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并且能节省内存空间
缺点:应用程序如果希望访问游离状态代理类实例,必须保证他在持久化状态时已经被初始化
迫切左外连接检索
优点
1、对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便地冲一个对象导航到与它关联的对象
2、使用了外连接, select 语句数目少
缺点
1、可能会加载应用程序不需要访问的对象,白白浪费许多内存空间
2、复杂的数据库表连接也会影响检索性能

5.Struts2

5.1 Struts2介绍

Struts2框架是一个按照MVC设计模式设计的WEB层框架是在struts 1 和 WebWork 的技术基础上进行了合并的全新的框架。其全新的 Struts 2 的体系结构与 Struts 1 的体系结构差别巨大。

Struts 2 以 WebWork 为核心,采用拦截器的机制来处理用户的请求, 这样的设计也使得业务逻辑控制器能够与 ServletAPI 完全脱离开
我们可以把 Struts2 理解为一个大大的 servlet,而这个 servlet 就是 ActionServlet

Struts2 在处理客户端请求时, 会先读取 web.xml 配置文件,根据前端控制器将符合条件的请求分给各个不同的 Action 处理。 在此之前,ActionServlet 会把数据封装成一个 javaBean。
Struts2 框架提供了许多的拦截器,在封装数据的过程中,我们可以对数据进行一些操 作,例如:数据校验等等。
当 Action 执行完后要返回一个结果视图, 这个结果视图可以跟据 struts2 的配置文件中 配置,选择转发或者重定向

总结就是,Struts2,它是一个基于mvc设计思想的前端web层框架,主要作用就是对前端请求进行处理。他的核心是拦截器,但是他的前端控制器是一个过滤器

5.2 struts1和struts2的区别

一个是Stuts1 ,一个是Stuts2,这是最大的区别,技术方面,Stuts1有个核心控制器,但是只提供了一个接口,也就是execute,还要配置actionform之类的,很麻烦,所以依赖性比较强;而Stuts2是针对拦截器开发的,也就是所谓的AOP思想,可以配置多个action,用起来比较方便,但是因为请求之前的拦截器有一些注入的操作,速度相对Stuts1来说慢一点

5.3 Struts2的优缺点

优点

Struts2比Struts1已经有了很大的进步,优点很多,其中主要两个是:对框架API和ServletAPI的依赖减少,可扩展性提高

Struts2的Action可以实现框架提供的Action接口也可以不实现这个接口。实际上框架Struts2的Action的要求很低,只要一个类,包含一个无参的、返回值类型为String的方法就行。其实Struts2的Action就是一个POJO。如果用户写一个类实现框架提供的Action接口或者继承框架提供的ActionSupport类, 则可以利用框架中的其他一些功能。比如在,Action接口中定义了一些常量,这些常量通常作为返回值共处理方法调用

由于Struts2的Action对框架API和Servlet API的依赖减少,因此可测程度大大提高

Struts2的可扩展性提高了。Struts2的核心jar包中由一个struts-default.xml文件,在该文件中设置了一些默认的bean,resultType类型,默认拦截器栈等,所有这些默认设置,用户都可以利用配置文件更改,可以更改为自己开发的bean,resulttype等

因此用户开发了插件的话只要很简单的配置就可以很容易的和Struts2框架融合,这实现了框架对插件的可插拔的特性

面向切面编程的思想在Strut2中也有了很好的体现。最重要的体现就是拦截器的使用。拦截器就是一个一个的小功能单位,用户可以将这些拦截器合并成一个大的拦截器,这个合成的拦截器就像单独的拦截器一样,只要将它配置到一个Action中就可以

缺点

在并发量比较大的场景中,每次请求都要创建一个Action,并维护很长的调用链(至少18个拦截器+OGNL解析+Action+Result),资源消耗比较大

5.4 拦截器和过滤器的区别

拦截器是基于 java 的反射机制的,而过滤器是基于函数回调

拦截器不依赖与 servlet 容器,而过滤器依赖与 servlet 容器

拦截器只能对 action 请求起作用,而过滤器则可以对几乎所有的请求起作用

拦截器可以访问 action 上下文、值栈里的对象,而过滤器不能

在 action 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作

5.5 Struts2的封装方式

1.属性封装

2.模型驱动(常用)

3.表达式封装

5.6 Struts2的值栈

值栈是对应每一个请求对象的数据存储中心,Struts2 的一个很重要的特点就是引入了值栈

之前我们通过缓存或者模型驱动在 action 和页面之间传递数据,数据混乱,并且难以管理,缓存还有时间和数量限制,使用起来非常的困难。值栈的引入解决了这个问题,它可以统一管理页面和 action 之间的数据,供 action、 result、 interceptor 等使用。我们大多数情况下不需要考虑值栈在哪里,里面有什么,只需要去获取自己需要的数据就可以了,大大的降低了开发人员的工作量 和逻辑复杂性

5.7 Struts2 中的 # 和 % (未完成)

猜你喜欢

转载自blog.csdn.net/weixin_42857002/article/details/82468762
今日推荐