Spring原理

Spring特点

轻量级,控制反转,面向切面,容器,框架集合

  • 轻量级
    从大小与开销两方面而言Spring都是轻量级得。完整得Spring框架可以在一个大小只用1M多的JAR文件里发布,并且Spring所需的处理开消也是微不足道的。
    此外,Sirng是非侵入式的:典型的,Spring应用中的对象不依赖于Spring的特定类。
  • 控制反转
    Spring通过一种称为控制反转IOC的技术促进了低耦合。
    当应用了IOC,一个对象的依赖的其他对象会通过被动的方式传递过来,而不是这个对象自己创建或查找依赖对象。
  • 面向切面
    Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开
  • 容器
    Spirng包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建。。。基于一个可配置原型,你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例。。。以及它们是如何相互关联的。
  • 框架
    Spirng可以将简单的组件配置,组合成复杂的引用。
    在spring中,应用对象被声明式的组合,典型的是在一个XML文件里。
    Spring也提供了很多基础功能(事务管理,持久化框架集成等),将应用逻辑的开发留给开发者。

Spring的核心组件

在这里插入图片描述

Spring常用模块

  • 核心容器
    核心容器提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转(IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring上下文
    Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下问包括企业服务,例如JNDI,EJB,电子邮件,国际化,检验和调度功能。
  • Spring AOP
    通过配置管理特性,Spring AOP模块直接将面向切面的编程功能集成到了Spring框架中。可以将一些通用任务,如安全,事务,日志等集中进行管理,提高了复用性和管理的便捷性。
  • Spring DAO
    为JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误信息,异常层次结构简化了错误处理,并且极大的降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAOde1mianxiang1JDBC的异常遵从通用的DAO异常层次结构。
  • Spring ORM
    Spring 框架插入了若干个ORM可见,从而提供了ORM的对象关系工具,其中包括JDO,Hibernate和iBatis SQL Map。所以这些都遵从Spring的通用事务和DAO异常层次结构。
  • Spring Web模块
    Web上下问模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。所以,Spring支持与Jakarta Structs的集成。Web模块还简化了处理多部份请求以及将请求参数数据绑定到域对象的工作。
  • Spring MVC框架
    MVC框架是一个全功能的构建Web应用程序的MVC实现,通过策略接口,MVC框架变成为高度可配置的,MVC容纳了大量视图技术,其中包括JSP,Velocity,Tiles,iText和POI。

Spring中主要的包

在这里插入图片描述

Spring常用注解

bean注入与装配的方式有多种,可以通过xml,get,set方式,构造函数或者注解等。简单易用的方式就是使用Spring的注解了,Spring提供了大量的注解方式。

@Controller

  • 用于标注控制层组件
  • @Controller用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller对象。
  • 分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解
  • 可以把Request请求header部分的值绑定到方法的参数上。

@RestController

相当于@Controller和@ResponseBody的组合效果

@Component

泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注

@Repository

用于注解dao层,在daoImpl类上面注解

@Service

用于标注业务层组件

@ResponseBody

  • 异步请求
  • 该注解用于将Controller的方法返回的对象,通过插件HttpMessageConvecter转换为指定格式后,写入到Response对象的body数据区。
  • 返回的数据不是html标签的页面,而是其他某种格式的数据时(json,xml等)使用。

@RequestMapping

一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中所有响应请求的方法都是以该地址就作为父路径。

@Autowired

它可以对类成员变量,方法及构造函数进行标注,完成自动装配的工作,通过@Autowired的使用来消除set,get方法

@PathVarlable

用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出url模板中的变量作为参数

@requestParam

主要用于在SpirngMVC后台控制层获取参数,类似一种是request.getParameter(“name”)

@RequestHeader

可以把Reqeust请求header部分的值绑定到方法的参数上

@ModelAttribute

该controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller集成BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。

@SessionAttribute

即将值放到session作用域中,写在class上面

@Valid

实体数据校验,可以结合hibernate validator一起使用

@CookieValue

用来获取Cookie中的值

Spring和一些第三方结合

在这里插入图片描述

Spring IOC原理

概念

Spring通过一个配置文件描述Bean及Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。Spring的IOC容器在完成这些底层工作的基础上,还提供了Bean实例缓存,生命周期管理,Bean实例代理,事件发布,资源装载等高级服务。

Spring容器高层视图

Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册标,然后根据这张注册标实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境,其中Bean缓存池为HashMap实现
在这里插入图片描述

IOC容器实现

BeanFactory-框架基础设施

BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合我们都直接使用ApplicationContext而非底层的BeanFactory。
在这里插入图片描述

  • BeanDefinitionRegistry注册表
    Spring配置文件中每一个节点元素在Spring容器里都通过一个BeanDefinition对象表示,它描述了Bean的配置信息。而BeanDefinitionRegistry接口提供了向容器手工注册BeanDefinition对象的方法
  • BeanFactory顶层接口
    位于类结构树的顶端,它最主要的方法就是getBean(Strng beanName),该方法从容器中返回特定名称的Bean,BeanFactory的功能通过其他的接口得到不断扩展;
  • ListableBeanFactory
    该接口定义了访问容器中Bean基本信息的若干方法,如查看Bean的个数,获取某一类型Bean的配置名,查看容器中是否包括某一Bean等方法;
  • HierarchicalBeanFactory父子级联
    HierarchicalBeanFactory接口,Spring的IOC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,但父容器不能访问子容器中的Bean,Spring使用父子容器实现了很多功能,比如在Spring MVC中,展现层Bean位于一个子容器中,而业务层和持久层的Bean位于父容器中。这样,展现层Bean就可以引用业务层和持久层的Bean,而业务层和持久层的Bean则看不到展现层的Bean。
  • ConfigurableBeanFactory
    是一个重要的接口,增强了IOC容器的可定制性,它定义了设置类装载器,属性编辑器,容器初始化后置处理器等方法;
  • AutowireCapableBeanFactory自动装配
    定义了将容器中的Bean按某种规则(如按名字匹配,按类型匹配等)进行自动装配的方法;
  • SingletonBeanRegistry
    定义了允许在运行期间向容器注册单例Bean的方法;对于单实例(singleton)的Bean来说,BeanFactory会缓存Bean实例,所以第二次使用getBean()获取Bean时将直接从IOC容器的缓存中获取Bean实例。Spring在DefaultSingletonBeanRegistry类中提供了一个用于缓存单实例Bean的缓存器,它是一个用HashMap实现的缓存器,单实例的Bean以beanName为键保存在这个HashMap中。
  • 依赖日志框架
    在初始化BeanFactory时,必须为其提供一种日志框架,比如使用Log4J,即在类路径下提供Log4J配置文件,这样启动Spring容器才不会报错。

ApplicationContext面向开发应用

ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。ApplicationContext集成了HierarchicalBeanFactory和ListableBeanFactory接口,在此基础上,还通过多个其他的接口扩展了BeanFactory的功能:
在这里插入图片描述

  • ClassPathXmlApplicationContext:默认从类路径加载配置文件
  • FileSystemXmlApplicationContext:默认从文件系统中装配配置文件
  • ApplicationEc=ventPublisher:让容器拥有发布应用上下文事件的功能,包括容器启动事件,关闭事件等。
  • MessageSource:为应用提供i18n国际化消息访问功能;
  • ResourcePatternResolver:所有ApplicationContext实现类都实现了类似于PathMatchingResourcePattermResolver的功能,可以通过带前缀的Ant风格的资源文件路径装载Spring的配置文件。
  • LifeCycle:该接口是Spring2.0加入的,该接口提供了start()和stop()两个方法,主要用于控制异步处理过程。具体使用时,该接口同时被ApplicationContext实现及具体Bean实现,ApplicatioContext会将start/stop的消息传递给容器中所有实现了该接口的Bean,以达到管理和控制JMX,任务调度等目的。
  • ConfigurableApplicationContext扩展于ApplicationContext,它新增加了两个主要方法:refresh(0和close(),让Application具有启动,刷新和关闭应用上下问的能力。在应用上下问关闭的情况下调用refresh()即可启动应用上下文,在已经启动的状态下,调用refresh()则清除缓存并重新装载配置信息,而调用close()则关闭应用上下文。

WebApplicatiob体系架构

WebApplicationContext是专门为Web应用准备的,它允许相对于Web根目录的路径中装载的配置文件完成初始化工作。从WebApplicationContext中可以获得ServletContext的引用。整个WEB应用上下文对象将作为属性放置到ServletContext中,以便Web应用环境可以访问到Spring应用上下文。
在这里插入图片描述

Spring Bean作用域

Spirng 3中为Bean定义了5种作用域,分别为singleton(单例),prototype(原型),request,session和global session

  • singleton:单例模式(多线程下不安全)
    singleton:单例模式,Spring IOC容器中只会存在一个共享的Bean实例,无论有多少个Bean引用它,始终指向同一对象。该模式在多线程下是不安全。Singleton作用域是Spring中的缺省作用域,也可以显示的将Bean定义为singleton模式,配置为:
    < bean id=“userDao” class=“com.ioc.userdaoimpl” scope=“singleton” />
  • prototype:原型模式每次使用时创建
    prototype:原型模式,每次通过Spring容器获取prototype定义的bena时,容器将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态,而singleton全局只有一个对象.根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域.
  • Request:一次request一个实例
    request:在一次Http请求中,容器会返回该Bean的同一实例,而对不同的Htpp请求则会产生新的Bean,而对该bean仅在当前Http Request内有效,当前Http请求结束,该bean实例也将会被销毁.
    < bean id =“loginAction” class=“com.cnblogs.login” scope=“requset” >
  • session
    session:在一次Http Session中,容器会返回该Beean的同一实例,而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效.同Http请求,每一次session请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的session请求内有效,请求结束,该实例将被销毁.
    < bean id =“userPreference” class=“com.ioc,UserpRreference” scope=“session” />
  • global Session
    global Sessiob:在一个全局的Http Session中,容器会返回该Bean的同一实例,仅在使用portlet context时有效.

Spring Bean生命周期

  • 实例化
    实例化一个Bean,也就是我们常说的new
  • IOC依赖注入
    按照Spring 上下文对实例化Bean进行配置,也就是IOC注入.
  • setBeanName实现
    如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的 id值
  • BeanFactoryAware
    如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory,setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其他Bean,只需要在Spring配置文件中配置一个普通的Bean就可以了)
  • ApplicationContextAware实现
    如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现BeanFactoryAware的内容,而且比其要好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法)
  • postProcessBeforeInitialization接口实现-初始化预处理
    如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj,String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术.
  • init-method
    如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法.
  • postProcessAfterInitialization
    如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj,String s)方法.
    注意:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个singleton的,所以一般情况下我们调用一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton.
  • Destroy 过期自动清理阶段
    当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destory()方法.
  • destroy-method 自配置清理
    最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法.
    在这里插入图片描述
  • bean标签有两个重要的属性(init-method和destroy-method).用它们可以自己定制初始化和注销方法.它们也有相应的注解(@PostConstruct和@PreDestroy).

Spring 依赖注入四种方式

  • 构造器注入
/*带参数,方便利用构造器进行注入*/ 
 public CatDaoImpl(String message){ 
 this. message = message; 
 } 
<bean id="CatDaoImpl" class="com.CatDaoImpl"> 
<constructor-arg value=" message "></constructor-arg>
  • setter方法注入
 public class Id { 
 private int id; 
 public int getId() { return id; } 
 public void setId(int id) { this.id = id; } 
} 
<bean id="id" class="com.id "> <property name="id" value="123"></property> </bean>
  • 静态工厂注入
    静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让spring管理所有对象,我们不能直接通过"工程类.静态方法()"类获取对象,而是依然通过spring注入的形式获取:
public class DaoFactory { //静态工厂 
 public static final FactoryDao getStaticFactoryDaoImpl(){ 
 return new StaticFacotryDaoImpl(); 
 } 
} 
public class SpringAction { 
 private FactoryDao staticFactoryDao; //注入对象
 //注入对象的 set 方法 
 public void setStaticFactoryDao(FactoryDao staticFactoryDao) { 
 this.staticFactoryDao = staticFactoryDao; 
 } 
} 
//factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法
 <bean name="springAction" class=" SpringAction" > 
 <!--使用静态工厂的方法注入对象,对应下面的配置文件--> 
 <property name="staticFactoryDao" ref="staticFactoryDao"></property> 
 </bean> 
 <!--此处获取对象的方式是从工厂类中获取静态方法--> 
<bean name="staticFactoryDao" class="DaoFactory" 
factory-method="getStaticFactoryDaoImpl"></bean>
  • 实例工厂
    实例工厂的意思是获取对象实例的方法不是静态的,所以需要首先new 工厂类,再调用普通的实例方法:
public class DaoFactory { //实例工厂 
 public FactoryDao getFactoryDaoImpl(){ 
 return new FactoryDaoImpl();
  } 
} 
public class SpringAction { 
 private FactoryDao factoryDao; //注入对象 
 public void setFactoryDao(FactoryDao factoryDao) { 
 this.factoryDao = factoryDao; 
 } 
} 
 <bean name="springAction" class="SpringAction"> 
 <!--使用实例工厂的方法注入对象,对应下面的配置文件--> 
 <property name="factoryDao" ref="factoryDao"></property> 
 </bean> 
 <!--此处获取对象的方式是从工厂类中获取实例方法--> 
<bean name="daoFactory" class="com.DaoFactory"></bean> 
<bean name="factoryDao" factory-bean="daoFactory"
factory-method="getFactoryDaoImpl"></bean>

5种不同方式的自动装配

Spring装配包括手动装配和自动装配,手动装配是有基于xml装配,构造方法,setter方法等,自动装配有5种自动装配的方式,可以用来指导Spring容器用自动装配的方式注入.

  1. no:默认的方式是不进行自动装配,通过显示设置ref属性来进行装配
  2. byName:通过参数名,自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byName,之后容器试图匹配,装配和该bean的属性具有相同名字的bean.
  3. byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配,装配和该bean的属性具有相同类型的bean.如果有多个bean符合条件,则会抛出错误
  4. constructor:这个方法类似于byType,但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常
  5. autodetect:首次尝试使用constructor来自动装配,如果无法工作,则使用byType方式.

Spring AOP的原理

概念

"横切"得技术,剖解开封装得对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect’,即切面,所谓切面,简单来说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块的耦合度,并有利于未来的可操作性和可维护性.
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点.业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点.横切关注点的一个特点是,他们经常发生在核心关注点多处,而各处基本相似,比如权限认证,日志,事务.AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来.

AOP主要应场景有:

在这里插入图片描述

AOP核心概念

  1. 切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
  2. 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称为横切关注点
  3. 连接点(join point):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器.
  4. 切入点(pointcute):对连接点进行拦截的定义
  5. 通知(advice):所谓通知指的就是指拦截到的连接点之后要执行的代码,通知分为前置,后置,异常,最终,环绕通知五类
  6. 目标对象:代理的目标对象
  7. 织入(weave):将切面应用到目标对象并导致代理对象创建的过程
  8. 引入(introduction):不修改代码的前提下,引入可以在运行期为类动态的添加一些方法或字段.
    在这里插入图片描述

AOP两种代理方式

Spring提供了两种方式来生成代理对象:JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。

  • JDK动态接口代理
    JDK动态代理主要设计到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类代码,动态将横切逻辑和业务逻辑编制再一起。Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
  • Cglib动态代理
    Cglib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,Cglib封装了asm,可以在运行期动态生成新的class,和JDK动态代理相比,JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过Cglib创建动态代理。

实现原理

@Aspect
public class TransactionDemo {
 @Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
 public void point(){
 }
 @Before(value="point()")
 public void before(){
 System.out.println("transaction begin");
 }
 @AfterReturning(value = "point()")
 public void after(){
 System.out.println("transaction commit");
 }
 @Around("point()")
 public void around(ProceedingJoinPoint joinPoint) throws Throwable{
 System.out.println("transaction begin");
 joinPoint.proceed();
 System.out.println("transaction commit");
 } }

SpringMVC的原理

Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射,试图渲染,本地化,时区与主题渲染等,甚至还能支持文件上传。

MVC流程

在这里插入图片描述

  • Http请求到DispatcherServlet
  1. 客户端请求提交到DispatcherServlet
  • HandlerMapping寻找处理器
    2)由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的controller。
  • 调用处理器controller
    3)DispatcherServlet将请求提交到Controller。
  • Controller调用业务逻辑处理后,返回ModelAndView
    4)5)调用业务处理和返回结果:Controller调用业务逻辑处理后,返回ModelAndView。
  • DispatcherServlet查询ModelAndView
    6)7)处理视图映射并返回模型:DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModerAndView指定的视图。
  • ModelAndView反馈浏览器HTPP
    8)Http响应:视图负责将结果显示到客户端。

SpringMVC常用注解

在这里插入图片描述
在这里插入图片描述

SpringBoot原理

SringBoot的特点

  1. 创建独立的Spring应用程序
  2. 嵌入式的Tomcat,无序部署WAR文件
  3. 简化Maven配置
  4. 自动配置Spring
  5. 提供生成就绪型功能,如指标,健康检查和外部配置
  6. 绝对没有代码生成和对XML没有要求配置

JPA的原理

  • 事务
    事务是计算机应用中不可或缺的组件模型,他保证了用户操作的原子性(Atomicity),一致性(Consistency),隔离性(lsolation)和持久性(Durabilily)
  • 本地事务
    紧密依赖于底层资源管理器(例如数据库连接),事务处理局限在当前事务资源内。此种事务处理方式不存在对应用服务器的依赖,因而部署灵活而无法支持多数据源的分布式事务。在数据库连接中使用本地事务实例如下:
public void transferAccount() { 
Connection conn = null; 
Statement stmt = null; 
try{ 
conn = getDataSource().getConnection(); 
// 将自动ᨀ交设置为 false,若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动ᨀ交
conn.setAutoCommit(false);
stmt = conn.createStatement(); 
// 将 A 账户中的金额减少 500
stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500 
stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'");
// ᨀ交事务
 conn.commit();
 // 事务ᨀ交:转账的两步操作同时成功
} catch(SQLException sqle){ 
// 发生异常,回滚在本事务中的操做
 conn.rollback();
// 事务回滚:转账的两步操作完全撤销
 stmt.close(); 
 conn.close(); 
} 
}
  • 分布式事务
    Jav事务编程接口(JTA:Java Transaction API)和Java事务服务(JTS: jAVA Transaction Service)为J2EE平台提供了分布式事务服务。分布式事务(Distributed Transaction)包括事务管理器(Transaction Manager)和一个或多个支持XA协议的资源管理器(Resource Manager)。我们可以将资源管理器看作任意类型的持久化数据库存储;事务管理器承担着所有事务参与单元的协调控制。
public void transferAccount() { 
UserTransaction userTx = null; 
Connection connA = null; Statement stmtA = null; 
Connection connB = null; Statement stmtB = null; 
try{ 
// 获得 Transaction 管理对象
userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction"); 
connA = getDataSourceA().getConnection();// 从数据库 A 中取得数据库连接
connB = getDataSourceB().getConnection();// 从数据库 B 中取得数据库连接
userTx.begin(); // 启动事务
stmtA = connA.createStatement();// 将 A 账户中的金额减少 500 
stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500 
stmtB = connB.createStatement();
stmtB.execute("update t_account set amount = amount + 500 where account_id = 'B'");
userTx.commit();// 提交事务
// 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
} catch(SQLException sqle){ 
// 发生异常,回滚在本事务中的操纵
 userTx.rollback();// 事务回滚:数据库 A 和数据库 B 中的数据更新被同时撤销
} catch(Exception ne){ } 
}
  • 两阶段提交
    两阶段提交主要保证了分布式事务的原子性:即所有节点要么全做,要么全不做,所谓两阶段是指:第一阶段:准备阶段;第二阶段:提交阶段。
    在这里插入图片描述
  1. 准备阶段
    事务协调者(事务管理器)给每个参与者(资源管理器)发送Prepare消息,每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的redo和undo日志,但不提交,到达一种“万事俱备,只欠东风”的状态
  2. 提交阶段
    如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(commit)消息;参与者根据协调者的指令执行提交或回滚操作,释放所有事务处理过程中使用的锁资源(注意:必须要在最后阶段释放锁资源
    将提交分成两阶段进行的目的很明确,就是尽可能晚的提交事务,让事务在提交前尽可能完成所有可能完成的工作。

MyBatis缓存

MyBatis中有一级和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指SqlSession级别的缓存,当在同一个SqlSession中进行相同的SQL语句查询时,第二次以后的查询不会从数据库查询,而是直接从换从中获取,一级缓存最多缓存1024条SQL,二级缓存是指可以跨SqlSession的缓存。是mapper级别的缓存,对于mapper界别的缓存不同的sqlsession是可以共享的。
在这里插入图片描述

Mybatis的一级缓存原理(sqlsession级别)

第一次发出一个sql,sql查询结果写入sqlsession的一级缓存中,缓存使用的数据结构是一个map。

  • key:MapperID+offset+limit+sql+所有的入参
  • value:用户信息
    同一个sqlsession再次发出相同的sql。就会从缓存中取出数据,如果两次中间出现commit操作(修改,添加,删除),本sqlsession中的一级缓存区域全部清空,下次再去缓存查询不到所以要从数据库查询,从数据查询到再写入缓存。

二级缓存原理(mapper基本)

二级缓存的范围是mapper级别(mapper同一个命名空间),mapper以命名空间为单位创建缓存数据结构,
结构是map。Mybatis的二级缓存是通过CacheExecutor实现的。CacherExecutor其实是Executor的代理对象。所有的查询操作,在CacheExecutor中都会先匹配缓存中是否存在,不存在则查询数据库。
key:MapperID+offset+limit+Sql+所有的入参
具体使用需要配置:

  1. MyBatis全局配置中启用二级缓存配置
  2. 在对应的Mapper.xml中配置cache节点
  3. 在对应的select查询节点添加useCache=true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值