Spring

Spring

1. Spring

1.1 框架介绍

Spring 是于 2003 年兴起的一个轻量级的 Java 开发框架,它是为了解决企业应用开发 的复杂性而创建的。

Spring 的核心是控制反转(IoC)和面向切面编程(AOP)。能实现模块之间,类之间的解耦合。Spring 是可 以在 Java SE/EE 中使用的轻量级开源框架。

Spring 的主要作用就是为代码**“解耦”**,降低代码间的耦合度。就是让对象和对象(模块和模块)之间关系不是使用代码关联,而是通过配置来说明。即在 Spring 中说明对象(模块)的关系。

Spring 根据代码的功能特点,使用 Ioc 降低业务对象之间耦合度。IoC 使得主业务在相互 调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由 Spring 容器统一管理,自动“注入”,注入即赋值。 而 AOP 使得系统级服务得到了最大复用,且 不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成 “织入”。

官网:https://spring.io/

1.2 优点
  • (1) 轻量

    Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring 核心功能的所需 的 jar 总共在 3M 左右。 Spring 框架运行占用的资源少,运行效率高。不依赖其他 jar

  • (2) 针对接口编程,解耦合

    Spring 提供了 Ioc 控制反转,由容器管理对象,对象的依赖关系。原来在程序代码中的 对象创建方式,现在由容器完成。对象之间的依赖解耦合。

  • (3) AOP 编程的支持

    通过 Spring 提供的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现 的功能可以通过 AOP 轻松应付 在 Spring 中,开发人员可以从繁杂的事务管理代码中解脱出来,通过声明式方式灵活地 进行事务的管理,提高开发效率和质量。

  • (4) 方便集成各种优秀框架

    Spring 不排斥各种优秀的开源框架,相反 Spring 可以降低各种框架的使用难度,Spring 提供了对各种优秀框架(如 Struts,Hibernate、MyBatis)等的直接支持。简化框架的使用。 Spring 像插线板一样,其他框架是插头,可以容易的组合到一起。需要使用哪个框架,就把 这个插头放入插线板。不需要可以轻易的移除。

1.3 体系结构图

在这里插入图片描述

Spring 由 20 多个模块组成,它们可以分为

数据访问/集成(Data Access/Integration)

Web

面向切面编程(AOP, Aspects)

提供JVM的代理(Instrumentation)

消息发送(Messaging)

核心容器(Core Container)

测试(Test)

2. IoC 控制反转

2.1 IoC (Inversion of Control) : 控制反转, 是一个理论,概念,思想。

把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。

  • 控制: 创建对象,对象的属性赋值,对象之间的关系管理。

  • 反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 由容器代替开发人员管理对象。创建对象,
    给属性赋值。

    正转(之前一直使用的):由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。
    public static void main(String args[]){
    Student student = new Student(); // 在代码中, 创建对象。–正转。}

  • 容器:是一个服务器软件, 一个框架(spring)

2.2 为什么要使用 ioc : 减少对代码的改动, 也能实现不同的功能。 实现解耦合。
2.3 java中创建对象有哪些方式:
1. 构造方法 , new Student()
2. 反射
3. 序列化
4. 克隆
5. ioc :容器创建对象
6. 动态代理
2.4 ioc的体现:

servlet:

1:创建类继承HttpServelt
2:在web.xml 注册servlet , 使用

<servlet-name> myservlet </servlet-name>				                                 

<servelt-class>xxx.xxx.controller.MyServlet1</servlet-class>
  1. 没有创建 Servlet对象, 没有 MyServlet myservlet = new MyServlet()
  2. Servlet 是Tomcat服务器创建的。 Tomcat也称为容器
    Tomcat作为容器:里面存放的有Servlet对象,Listener ,Filter对象
2.5 IoC的技术实现 :

DI 是ioc的技术实现
DI(Dependency Injection):依赖注入, 只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建,
赋值,查找都由容器内部实现。

spring是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制

spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象。

spring-conetxt 和 spring-webmvc是spring中的两个模块

spring-context:是ioc功能的,创建对象的。
spring-webmvc做web开发使用的, 是servlet的升级。
spring-webmvc中也会用到spring-context中创建对象的功能的。

2.6基于 XML 的 DI
2.6.1 注入分类

bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化 是由容器自动完成的,称为注入。 根据注入方式的不同,常用的有两类:set 注入、构造注入。

  1. set 注入

    执行顺序:无参构造创建对象—》set方法完成赋值

  • 1 ) 简单类型的set注入:spring调用类的set方法, 可以在set方法中完成属性赋值
<bean id="xx" class="yyy">
    <property name=" 属性名字”value=" 此属性的值"/>
    一个property只能给一个属性赋值
    <property....
</bean>

set注入找的是类中的set方法,即使没有声明的变量,有set方法,依然可以执行

  • 2)引用类型的set注入 : spring调用类的set方法

    <bean id="xxx" class= "yyy">
        <property name="属性名称" ref="bean的id(对象的名称)"/>
    </bean>
    
  1. 构造注入

spring调用类有参数构造方法, 在创建对象的同时,在构造方法中给属性赋值。

构造注入使用 标签

<constructor-arg>标签:一个<constructor-arg>表示构造方法一个参数。
<constructor-arg>标签属性:
    name :表示构造方法的形参名
    index:表示构造方法的参数的位置,参 数从左往右位置是0,1, 2的顺序
    value :构造方法的形参类型是简单类型的,使用value
    ref :构造方法的形参类型是引用类型的,使用ref
2.6.2 引用类型属性自动注入
  1. byName 方式自动注入

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

语法:
<bean id="xx" class="yyy" autowire= "byName">
    简单类型属性赋值
</bean>
  1. byType 方式自动注入

byType(按类型注入) : java类中引用类型的数据类型和spring容器中(配置文件) 的class属性是同源关系的,这样的bean能够赋值给引用类型

同源就是一类的意思:
1.java类中 引用类型的数据类型和bean的class的值 是一样的。
2.java类中 引用类型的数据类型和bean的class的值 父子类关系的。
3.java类中 引用类型的数据类型和bean的class的值 接口和实现类关系的

语法:
<bean id="xx" class="yyy" autowire="byType">
	简单类型属性赋值
</bean>
2.6.3 为应用指定多个 Spring 配置文件

在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变 得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将 Spring 配置文件分解成多个配置文件

包含关系的配置文件:

多个配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java 代码中只需要使用总配置文件对容器进行初始化即可。

在包含关系的配置文件中,可以通配符( * :表示任意字符)
注意:主配置文件名称不能包含在通配符的范围内

  1. 多个配置优势
    • 每个文件的大小比一个文件要小很多。效率高
  • 避免多人竞争带来的冲突。

如果你的项目有多个模块(相关的功能在一起) ,一个模块一个配置文件。
学生考勤模块一个配置文件, 张三
学生成绩一个配置文件, 李四

多文件的分配方式:

  1. 按功能模块,一个模块一个配置文件
  2. 按类的功能,数据库相关的配置一个文件配置文件, 做事务的功能一个配置文件, 做service功能的一个配置文件等
2.7 基于注解的 DI

通过注解完成java对象创建,属性赋值。

使用注解的步骤:

  1. 加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring-aop的依赖。
    使用注解必须使用spring-aop依赖

  2. 在类中加入spring的注解(多个不同功能的注解)

  3. 在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置.

    学习的注解:
    1.@Component
    2.@Respotory
    3.@Service
    4.@Controller
    5.@Value
    6.@Autowired
    7.@Resource

@Component:

@Component: @Component:创建对象的,等同于的功能
属性:value 就是对象的名称,也就是bean的id值,
value的值是唯一的 ,创建的对象在整个spring容器中就个
位置:在类的上面

@component(value = "myStudent ”)等同于

spring中和@Component功能一致 ,创建对象的注解还有:
@Repository (用在持久层类的上面) :放在dao的实现类上面,表示创建dao对象, dao对象是能访问数据库的。

@Service(用在业务层类的上面) :放在service的实现关上面创建service对象, service对象是做业务处理,可以有事务等功能的。

@Controller(用在控制器的上面) : 放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果。

以上三个注解的使用语法Component一样的。都能创建对象,但是这三个注解还有额外的功能。
@Repository,@Service,@Controller是给项目对象分层的。

@Value:

@Value: 简单类型的属性赋值
属性: value 是string类型的 ,表示简单类型的属性值
位置: 1.在属性定义的上面,无需set方法,推荐使用。
2.在set方法的上面,类中无需 setter。当然,若属性有 setter,则也可将其加 到 setter 上。

Autowired:

引用类型
@Autowired: spring框架提供的注解,实现引用类型的赋值。
spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType
@Autowired:默认使用的是byType自动注入。

属性:required , 是一个boolean类型的,默认true
required=true :表示引用类型赋值失败,程序报错,并终止执行。
required=false :引用类型如果赋值失败,程序正常执行,引用类型是null

位置:1 )在属性定义的上面,无需set方法,推荐使用
2 )在set方法的上面

如果要使用byName方式,需要做的是:
1.在属性上面加@Autowired
2.在属性上面加@Qualifier(value= “bean的id”) :表示使用指定名称的bean完成赋值

JDK 注解@Resource 自动注入:

引用类型
@Resource:来自jdk 中的注解,spring 框架提供对这个注解的功能支持,可以使用它给引用类型赋值,使用的也是自动注入原理,支持byName, byType ,默认是byName

位置: 1.在属性定义的上面, 无需set方法,推荐使用。
2.在set方法的上面

默认是byName :先使用byName 自动注入,如果byName赋值失败, 再使用byType
@Resource只使用byName方式, 需要增加一个属性name
name的值是bean的id(名称)

2.7.1 注解与 XML 的对比
  1. 注解优点是:

方便 直观 高效(代码少,没有配置文件的书写那么复杂)。

​ 缺点:

以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。

  1. XML 方式优点是:

配置和代码是分离的 在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。

​ 缺点:

编写麻烦,效率低,大型项目过于复杂。

3.AOP

3.1 概述

AOP(Aspect Orient Programming),面向切面编程。面向切面编程是从动态角度考虑程序运行过程。

AOP 底层,就是采用动态代理模式实现的。

采用了两种代理:JDK 的动态代理,与 CGLIB 的动态代理。
实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
jdk动态代理要求目标类必须实现接口

cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。
子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的

AOP 是 Spring 框架中的一个重要内容。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

面向切面编程对有什么好处?

1.减少重复;

2.专注业务;

怎么理解面向切面编程 ?
1)需要在分析项目功能时,找出切面。
2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能

注意:面向切面编程只是面向对象编程的一种补充。 使用 AOP 减少重复代码,专注业务实现:

在这里插入图片描述

AOP 编程术语

(1) 切面(Aspect) 切面泛指交叉业务逻辑。例如事务处理、日志处理就可以理解为切面。常用的切面 是通知(Advice)。实际就是对主业务逻辑的一种增强。

(2) 连接点(JoinPoint) 连接点指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。 连接业务方法和切面的位置。 就某类中的业务方法。

(3) 切入点(Pointcut) 切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。 被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。

(4) 目标对象(Target) 目标对象指要被增强的对象 。即包含主业务逻辑的类的对象。上例中 的 StudentServiceImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然, 不被增强,也就无所谓目标不目标了。

(5) 通知(Advice) 通知表示切面的执行时间,Advice 也叫增强。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。 切入点定义切入的位置,通知定义切入的时间。

切面有三个关键的要素:
1)切面的功能代码,切面干什么
2)切面的执行位置,使用Pointcut表示切面执行的位置
3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。

3.2 AspectJ

对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向 切面编程。然而,AspectJ 也实现了 AOP 的功能,且其实现方式更为简捷,使用更为方便, 而且还支持注解式开发。所以,Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框架中。

在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。

官网地址:http://www.eclipse.org/aspectj/

aspectJ框架实现aop有两种方式:
1.使用xml的配置文件 : 配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。

aspectj框架的使用:

1)切面的执行时间, 这个执行时间在规范中叫做Advice(通知,增强)
在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After

2)表示切面执行的位置,使用的是切入点表达式。
com.service.impl
com.bjpowrnode.service.impl
cn.crm.bjpowernode.service

3.3 切入点表达式

表达式的原型是:

execution(modifiers-pattern? ret-type-pattern 
		declaring-type-pattern?name-pattern(param-pattern) 
		throws-pattern?) 

在这里插入图片描述

以上表达式共 4 个部分。 execution(访问权限 方法返回值 方法声明(参数) 异常类型)

切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中明显就 是方法的签名。注意,表达式中黑色文字表示可省略部分,各部分间用空格分开。在其中可 以使用以下符号:

在这里插入图片描述

举例:
在这里插入图片描述

3.4 AspectJ 基于注解的 AOP 实现
  • @Aspect:是aspectj框架中的注解。

作用:表示当前类是切面类。
切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
位置:在类定义的上面

定义方法,方法是实现切面功能的。
方法的定义要求:
1.公共方法 public
2.方法没有返回值
3.方法名称自定义
4.方法可以有参数,也可以没有参数。
如果有参数,参数不是自定义的,有几个参数类型可以使用。

  • @Before: 前置通知注解-方法有 JoinPoint 参数

属性:value,是切入点表达式 ,表示切面的功能执行的位置。
位置:在方法的上面
特点:
1.在目标方法之前先执行的
2.不会改变目标方法的执行结果
3.不会影响目标方法的执行。

  • 指定通知方法中的参数: JoinPoint

JoinPoint:业务方法,要加入切面功能的业务方法
作用是:可以在通知方法中获取方法执行时的信息,例如 方法名称 ,方法的实参。
如果你的切面功能中需要用到方法的信息,就加入JoinPoint.
这个JoinPoint参数的值是由框架赋予,必须是 第一个位置的参数

  • @AfterReturning:后置通知-注解有 returning 属性

    属性: 1.value切入点表达式

    ​ 2.returning自定义的变量,表示目标方法的返回值的。
    自定义变量名必须和通知方法的形参名一样。
    位置:在方法定义的上面
    特点:
    ​ 1.在目标方法之后执行的。
    ​ 2.能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
    ​ 3.可以修改这个返回值

  • @Around: 环绕通知-增强方法有 ProceedingJoinPoint 参数

环绕通知方法的定义格式
1.public
2.必须有个返回值, 推荐使用Object
3.方法名称自定义
4.方法有参数,固定的参数ProceedingJoinPoint

属性:value切入点表达式
位置:在方法的定义什么
特点:
1.它是功能最强的通知
2.在日标方法的前和后都能增强功能。
3.控制目标方法是否被调用执行
4.修改原来的目标方法的执行结果。 影响最后的调用结果

环绕通知,等同jdk动态代理的,InvocationHandler接口

参数:ProceedingJoinPoint 就等同FMe thod

作用:执行目标方法的

返回值:就是目标方法的执行结果,可以被修改。

环绕通知:经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务.

  • @AfterThrowing 异常通知-注解中有 throwing 属性

属性:1. value切入点表达式
2. throwinng 自定义的变量,表示目标方法抛出的异常对象。变量名必须和方法的参数名一样
特点:
1.在目标方法抛出异常时执行的
2.可以做异常的监控程序,监控目标方法执行时是 不是有异常。
如果有异常,可以发送邮件,短信进行通知。

  • @After 最终通知

最终通知方法的定义格式

1.public
2.没有返回值
3.方法名称自定义
4.方法没有参数,
如果有是JoinPoint

属性: value 切入点表达式
位置:在方法的上面
特点:
1.总是会执行
2.在目标方法之后执行的

  • @Pointcut 定义切入点

定义和管理切入点,如果 你的项目中有多个切入点表达式是重复的,可以复用的。可以使用@Pointcut
属性:value切入点表达式
位置:在自定义的方法上面
特点:
当使用Pointcut定义在一个方法的上面, 此时这个方法的名称就是切入点表达式的别名。
其它的通知中, value属性就可以使用这个方法名称,代替切入点表达式了。

这个使用@Pointcut 注解 的方法一般使用 private 的标识方法,即没有实际作用的方法。

4. Spring 集成 MyBatis

把mybatis框架和spring集成在一起,向一个框架一样使用。

将 MyBatis 与 Spring 进行整合,主要解决的问题就是将 SqlSessionFactory 对象交由 Spring 来管理。所以,该整合,只需要将 SqlSessionFactory 的对象生成器 SqlSessionFactoryBean 注 册在 Spring 容器中,再将其注入给 Dao 的实现类即可完成整合。

实现 Spring 与 MyBatis 的整合常用的方式:扫描的 Mapper 动态代理

Spring 像插线板一样,mybatis 框架是插头,可以容易的组合到一起。插线板 spring 插 上 mybatis,两个框架就是一个整体。

  • 用的技术是:ioc 。
  • 为什么ioc:能把mybatis和spring集成在一起,像一个框架, 是因为ioc能创建对象。
    可以把mybatis框架中的对象交给spring统一创建, 开发人员从spring中获取对象。
    开发人员就不用同时面对两个或多个框架了, 就面对一个spring
mybatis使用步骤,对象
1.定义dao接口 ,StudentDao
2.定义mapper文件 StudentDao.xml
3.定义mybatis的主配置文件 mybatis.xml
4.创建dao的代理对象, StudentDao dao = SqlSession.getMapper(StudentDao.class);
List<Student> students  = dao.selectStudents();

要使用dao对象,需要使用getMapper()方法
怎么能使用getMapper()方法,需要哪些条件

  1. 获取SqlSession对象, 需要使用SqlSessionFactory的openSession()方法。
  2. 创建SqlSessionFactory对象。 通过读取mybatis的主配置文件,能创建SqlSessionFactory对象

需要SqlSessionFactory对象, 使用Factory能获取SqlSession ,有了SqlSession就能有dao , 目的就是获取dao对象
Factory创建需要读取主配置文件

我们会使用独立的连接池类替换mybatis默认自己带的, 把连接池类也交给spring创建。

主配置文件:
1.数据库信息

 <environment id="mydev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">//POOLED,连接池
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="123456"/>
            </dataSource>
  1. mapper文件的位置

    <mappers>
         <mapper resource="xxx/xxx/dao/StudentDao.xml"/>
         <!--<mapper resource="xxx/xxx/dao/SchoolDao.xml" />-->
     </mappers>
    

通过以上的说明,我们需要让spring创建以下对象

  1. 独立的连接池类的对象, 使用阿里的druid连接池
  2. SqlSessionFactory对象
  3. 创建出dao对象

需要学习就是上面三个对象的创建语法,使用xml的bean标签。

5. spring的事务处理

事务原本是数据库中的概念,在 Dao 层。但一般情况下,需要将事务提升到业务层, 即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。

在 Spring 中通常可以通过以下两种方式来实现对事务的管理:

(1)使用 Spring 的事务注解管理事务

(2)使用 AspectJ 的 AOP 配置管理事务

1. 什么是事务

mysql的时候,提出了事务。 事务是指一组sql语句的集合, 集合中有多条sql语句 可能是insert , update ,select ,delete, 我们希望这些多个sql语句都能成功,或者都失败, 这些sql语句的执行是一致的,作为一个整体执行。

2.在什么时候想到使用事务

当我的操作,涉及得到多个表,或者是多个sql语句的insert,update,delete。需要保证这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的。

在java代码中写程序,控制事务,此时事务应该放在那里呢?
service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句

3.通常使用JDBC访问数据库, 还是mybatis访问数据库怎么处理事务

jdbc访问数据库,处理事务 Connection conn ; conn.commit(); conn.rollback();
mybatis访问数据库,处理事务, SqlSession.commit(); SqlSession.rollback();
hibernate访问数据库,处理事务, Session.commit(); Session.rollback();

4. 3问题中事务的处理方式,有什么不足
  1. 不同的数据库访问技术,处理事务的对象,方法不同,需要了解不同数据库访问技术使用事务的原理
  2. 掌握多种数据库中事务的处理逻辑。什么时候提交事务,什么时候回滚事务
  3. 处理事务的多种方法。

总结: 就是多种数据库的访问技术,有不同的事务处理的机制,对象,方法。

5.怎么解决不足

spring提供一种处理事务的统一模型, 能使用统一步骤,方式完成多种不同数据库访问技术的事务处理。

使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理
使用spring的事务处理机制,可以完成hibernate访问数据库的事务处理。

在这里插入图片描述

6.处理事务,需要怎么做,做什么

spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了

  1. 事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback
    事务管理器是一个接口和他的众多实现类。

    接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
    实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
    mybatis访问数据库—spring创建好的是DataSourceTransactionManager
    hibernate访问数据库----spring创建的是HibernateTransactionManager

怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
声明数据库访问技术对于的事务管理器实现类, 在spring的配置文件中使用声明就可以了

例如,你要使用mybatis访问数据库,你应该在xml配置文件中
<bean id=“xxx" class="...DataSourceTransactionManager"> 
  1. 你的业务方法需要什么样的事务,说明需要事务的类型。
  1. 说明方法需要的事务:

事务的隔离级别:有4个值。

DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
➢ SERIALIZABLE:串行化。不存在并发问题。

  1. 事务的超时时间: TIMEOUT_DEFAULT 定义了事务底层默认的超时时限,sql 语句的执行时长。如果方法执行时超过了时间,事务就回滚。单位是秒, 整数值, 默认是 -1.

  2. 事务的传播行为 : 控制业务方法是不是有事务的, 是什么样的事务的。

7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。

PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_SUPPORTS
以上三个需要掌握的

PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED

a、 PROPAGATION_REQUIRED: 指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中;若当前没有事务,则创建一个新事务。这种传播行为是最常见的选择,也是 Spring 默认的事务传播行为。

b、PROPAGATION_SUPPORTS 指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。

c、 PROPAGATION_REQUIRES_NEW 总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。

  1. 事务提交事务,回滚事务的时机
  • 当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit

  • 当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
    运行时异常的定义: RuntimeException 和他的子类都是运行时异常, 例如NullPointException , NumberFormatException

  • 当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
    受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException
    在这里插入图片描述

Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一) 的实例时,才能通过 Java 虚拟机或者 Java 的 throw 语句抛出。

Error 是程序在运行过程中出现的无法处理的错误,比如 OutOfMemoryError、 ThreadDeath、NoSuchMethodError 等。当这些错误发生时,程序是无法处理(捕获或抛出) 的,JVM 一般会终止线程。

程序在编译和运行时出现的另一类错误称之为异常,它是 JVM 通知程序员的一种方式。 通过这种方式,让程序员知道已经或可能出现错误,要求程序员对其进行处理。

异常分为运行时异常与受查异常。 运行时异常,是 RuntimeException 类或其子类,即只有在运行时才出现的异常。如, NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException 等均属于 运行时异常。这些异常由 JVM 抛出,在编译时不要求必须处理(捕获或抛出)。但,只要代 码编写足够仔细,程序足够健壮,运行时异常是可以避免的。

受查异常,也叫编译时异常,即在代码编写时要求必须捕获或抛出的异常,若不处理, 则无法通过编译。如 SQLException,ClassNotFoundException,IOException 等都属于受查异常。

RuntimeException 及其子类以外的异常,均属于受查异常。当然,用户自定义的 Exception 的子类,即用户自定义的异常也属受查异常。程序员在定义异常时,只要未明确声明定义的 为 RuntimeException 的子类,那么定义的就是受查异常。

总结spring的事务
1.管理事务的是 事务管理和他的实现类
2.spring的事务是一个统一模型
1)指定要使用的事务管理器实现类,使用
2)指定哪些类,哪些方法需要加入事务的功能
3)指定方法需要的隔离级别,传播行为,超时

你需要告诉spring,你的项目中类信息,方法的名称,方法的事务传播行为。

7.spring框架中提供的事务处理方案
  1. 适合中小项目使用的, 注解方案。
    spring框架自己用aop实现给业务方法增加事务的功能, 使用**@Transactional注解**增加事务。
    @Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

使用@Transactional的步骤:

  • 1.需要声明事务管理器对象
 <bean id="xx" class="DataSourceTransactionManager">
  • 2.开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务。

spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知

	 @Around("你要增加的事务功能的业务方法名称")
	 Object myAround(){
       开启事务,spring给你开启
		  try{
		     buy(1001,10);
			  spring的事务管理器.commit();
		  }catch(Exception e){
         spring的事务管理器.rollback();
		  }
		 
	 }
  • 3.在你的方法的上面加入@Trancational
  1. **适合大型项目,**有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中
    声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。

实现步骤: 都是在xml配置文件中实现。

  • 1.要使用的是aspectj框架,需要加入依赖

    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-aspects</artifactId>
    		<version>5.2.5.RELEASE</version>
    	</dependency>
    
  • 2.声明事务管理器对象

<bean id="xx" class="DataSourceTransactionManager">

  • 3.声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)
  • 4.配置aop:指定哪些哪类要创建代理。

6. web项目中怎么使用容器对象。

  1. 做的是javase项目有main方法的,执行代码是执行main方法的,
    在main里面创建的容器对象
    ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);

  2. web项目是在tomcat服务器上运行的。 tomcat一起动,项目一直运行的。

需求:
web项目中容器对象只需要创建一次, 把容器对象放入到全局作用域ServletContext中。

怎么实现:
使用监听器 当全局作用域对象被创建时 创建容器 存入ServletContext

监听器作用:
1)创建容器对象,执行 ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);
2)把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)

监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener

源代码:

 private WebApplicationContext context;
 public interface WebApplicationContext extends ApplicationContext
ApplicationContext:javase项目中使用的容器对象
WebApplicationContext:web项目中的使用的容器对象

把创建的容器对象,放入到全局作用域
 key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
       WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
 value:this.context

 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        把数据库的配置信息,写在一个独立的文件,编译修改数据库的配置内容
        spring知道jdbc.properties文件的位置-->

    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--声明数据源DataSource, 作用是连接数据库的-->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <!--set注入给DruidDataSource提供连接数据库信息-->
        <!--使用属性配置文件中的数据,语法${key}-->
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="${jdbc.max}"/>
    </bean>

    <!--声明的是mybatis中提供的SqlSessionFactoryBean类, 这个类内部创建SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set注入,把数据库连接池付给了dataSource属性-->
        <property name="dataSource" ref="myDataSource"/>
        <!-- mybatis主配置文件的位置
            configLocation属性是Resource类型,读取配置文件
            它的赋值,使用value,指定文件的路径,使用classpath:表示文件的位置
        -->
        <property name="configLocation" value="classpath:mybatis.xml"/>
    </bean>
    <!-- 创建dao对象 ,使用SqlSession的getMapper (studentDao.class )
    MapperScannerConfigurer:在内部调用getMapper( )生成每个dao接口的代理对象。
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

        <!--指定sqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!--指定包名,包名是dao接口所在的包名。
            MapperScannerConfigurer会扫描这个包中的所有接口,把每一个接口都执行
            一次getMapper()方法 得到每个接口的dao对象。
            创建好的dao对象放入到spring的容器中的。dao对象的默认名称是接口名首字母小写
        -->
        <property name="basePackage" value="org.example.dao"/>
    </bean>

    <!--声明service-->
    <bean id="studentService" class="org.example.service.impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao"/>
    </bean>


</beans>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值