四、Spring 事务
官网下载地址
能源节点 spring 材料
视频观看地址
https://www.bilibili.com/vide…
4.1 Spring 的事务管理
事务本来是数据库中的概念,在 Dao 层。但个别状况下,须要将事务晋升到业务层,即 Service 层。这样做是为了可能应用事务的个性来治理具体的业 务。
在 Spring 中通常能够通过以下两种形式来实现对事务的治理:
(1)应用 Spring 的事务注解治理事务
(2)应用 AspectJ 的 AOP 配置管理事务
4.2 Spring 事务管理 API
Spring 的事务管理,次要用到两个事务相干的接口。
(1)事务管理器接口(重点)
事务管理器是 PlatformTransactionManager 接口对象。其次要用于实现 事务的提交、回滚,及获取事务的状态信息。
A、罕用的两个实现类
PlatformTransactionManager 接口有两个罕用的实现类:
DataSourceTransactionManager:应用 JDBC 或 MyBatis 进行数据库操作时应用。
HibernateTransactionManager:应用 Hibernate 进行长久化数据时应用。
B、Spring 的回滚形式(了解)
Spring 事务的默认回滚形式是:产生运行时异样和 error 时回滚,产生受 查 (编译) 异样时提交。不过,对于受查异样,程序员也能够手工设置其回滚形式。
C、回顾谬误与异样 (了解)
Throwable 类是 Java 语言中所有谬误或异样的超类。只有当对象是此类 (或其子类之一) 的实例时,能力通过 Java 虚拟机或者 Java 的 throw 语句抛出。
Error 是程序在运行过程中呈现的无奈解决的谬误,比方 OutOfMemoryError、ThreadDeath、NoSuchMethodError 等。当这些谬误产生时,程序是无奈解决(捕捉或抛出)的,JVM 个别会终止线程。
程序在编译和运行时呈现的另一类谬误称之为异样,它是 JVM 告诉程序员 的一种形式。通过这种形式,让程序员晓得曾经或可能呈现谬误,要求程序员对其进行解决。
异样分为运行时异样与受查异样。
运行时异样,是 RuntimeException 类或其子类,即只有在运行时才呈现 的异样。如,NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException 等均属于运行时异样。这些异样由 JVM 抛出,在 编译时不要求必须解决(捕捉或抛出)。但,只有代码编写足够认真,程序足 够强壮,运行时异样是能够防止的。
受查异样,也叫编译时异样,即在代码编写时要求必须捕捉或抛出的异 常,若不解决,则无奈通过编译。如 SQLException,ClassNotFoundException,IOException 等都属于受查异样。
RuntimeException 及其子类以外的异样,均属于受查异样。当然,用户 自定义的 Exception 的子类,即用户自定义的异样也属受查异样。程序员在定 义异样时,只有未明确申明定义的为 RuntimeException 的子类,那么定义的 就是受查异样。
(2)事务定义接口
事务定义接口 TransactionDefinition 中定义了事务形容相干的三类常量:事务隔离级别、事务流传行为、事务默认超时时限,及对它们的操作。
A、定义了五个事务隔离级别常量(把握)
这些常量均是以 ISOLATION_结尾。即形如 ISOLATION_XXX。
- DEFAULT:采纳 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ;Oracle 默认为 READ_COMMITTED。
- READ_UNCOMMITTED:读未提交。未解决任何并发问题。
- READ_COMMITTED:读已提交。解决脏读,存在不可反复读与幻读。
- REPEATABLE_READ:可反复读。解决脏读、不可反复读,存在幻读
- SERIALIZABLE:串行化。不存在并发问题。
B、定义了七个事务流传行为常量(把握)
所谓事务流传行为是指,处于不同事务中的办法在互相调用时,执行期间事务的保护状况。如,A 事务中的办法 doSome()调用 B 事务中的办法 doOther(),在调用执行期间事务的保护状况,就称为事务流传行为。事务传 播行为是加在办法上的。
事务流传行为常量都是以 PROPAGATION_ 结尾,形如 PROPAGATION_XXX。
- PROPAGATION_REQUIRED
- PROPAGATION_REQUIRES_NEW
- PROPAGATION_SUPPORTS
- PROPAGATION_MANDATORY
- PROPAGATION_NESTED
- PROPAGATION_NEVER
- PROPAGATION_NOT_SUPPORTED
a、PROPAGATION_REQUIRED:
指定的办法必须在事务内执行。若以后存在事务,就退出到以后事务中;若以后没有事务,则创立一个新事务。这种流传行为是最常见的抉择,也是
Spring 默认的事务流传行为。
如该流传行为加在 doOther()办法上。若 doSome()办法在调用 doOther() 办法时就是在事务内运行的,则 doOther()办法的执行也退出到该事务内执行。若 doSome()办法在调用 doOther()办法时没有在事务内执行,则 doOther()办法会创立一个事务,并在其中执行。
b、PROPAGATION_SUPPORTS
指定的办法反对以后事务,但若以后没有事务,也能够以非事务形式执行。
c、PROPAGATION_REQUIRES_NEW
总是新建一个事务,若以后存在事务,就将以后事务挂起,直到新事务执行结束。
C、定义了默认事务超时时限
常量 TIMEOUT_DEFAULT 定义了事务底层默认的超时时限,sql 语句的执 行时长。
留神,事务的超时时限起作用的条件比拟多,且超时的工夫计算点较复 杂。所以,该值个别就应用默认值即可。
4.3 程序举例环境搭建
举例:购买商品 trans_sale 我的项目
本例要实现购买商品,模仿用户下订单,向订单表增加销售记录,从商品表减 少库存。
实现步骤:
Step0:创立数据库表
创立两个数据库表 sale , goods
sale 销售表
goods 商品表
goods 表数据
Step1: maven 依赖 pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <version>5.1.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
插件
<build>
<resources>
<resource>
<directory>src/main/java</directory><!-- 所在的目录 - ->
<includes><!-- 包含目录下的.properties,.xml 文件都会
扫描到 -->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId> <version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
Step2:创立实体类
创立实体类 Sale 与 Goods
Step3:定义 dao 接口
定义两个 dao 的接口 SaleDao , GoodsDao
Step4:定义 dao 接口对应的 sql 映射文件
SaleDao.xml
GoodsDao.xml
Step5:定义异样类
定义 service 层可能会抛出的异样类 NotEnoughException
Step6:定义 Service 接口
定义 Service 接口 BuyGoodsService
Step7:定义 service 的实现类
定义 service 层接口的实现类 BuyGoodsServiceImpl
1) 类定义
2) Dao 属性
3) Buy 办法
Step8:批改 Spring 配置文件内容
申明 Mybatis 对象
申明业务层对象
Step9:定义测试类
定义测试类 MyTest。当初就能够在无事务代理的状况下运行了。
4.4 应用 Spring 的事务注解治理事务(把握)
通过 @Transactional 注解形式,可将事务织入到相应 public 办法中,实 现事务管理。
@Transactional 的所有可选属性如下所示:
- propagation:用于设置事务流传属性。该属性类型为 Propagation 枚举,默认值为 Propagation.REQUIRED。
- isolation:用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认值为 Isolation.DEFAULT。
- readOnly:用于设置该办法对数据库的操作是否是只读的。该属性为 boolean,默认值为 false。
- timeout:用于设置本操作与数据库连贯的超时时限。单位为秒,类型为 int,默认值为 -1,即没有时限。
- rollbackFor:指定须要回滚的异样类。类型为 Class[],默认值为空数组。当然,若只有一个异样类时,能够不应用数组。
- rollbackForClassName:指定须要回滚的异样类类名。类型为 String[],默认值为空数组。当然,若只有一个异样类时,能够不应用数组。
- noRollbackFor:指定不须要回滚的异样类。类型为 Class[],默认值为空数组。当然,若只有一个异样类时,能够不应用数组。
- noRollbackForClassName:指定不须要回滚的异样类类名。类型为 String[],默认值为空数组。当然,若只有一个异样类时,能够不应用数组。
须要留神的是,@Transactional 若用在办法上,只能用于 public 办法上。对于其余非 public 办法,如果加上了注解 @Transactional,尽管 Spring 不会报错,但不会将指定事务织入到该办法中。因为 Spring 会疏忽掉所有非 public 办法上的 @Transaction 注解。
若 @Transaction 注解在类上,则示意该类上所有的办法均将在执行时织入 事务。
实现注解的事务步骤:
复制 trans_sale 我的项目,新我的项目 trans_sale_annotation
1. 申明事务管理器
2. 开启注解驱动
transaction-manager:事务管理器 bean 的 id
3. 业务层 public 办法退出事务属性
4.5 应用 AspectJ 的 AOP 配置管理事务(把握)
应用 XML 配置事务代理的形式的有余是,每个指标类都须要配置事务代 理。当指标类较多,配置文件会变得十分臃肿。
应用 XML 配置参谋形式能够主动为每个合乎切入点表达式的类生成事务代 理。其用法很简略,只需将后面代码中对于事务代理的配置删除,再替换为如 下内容即可。
Step1:复制我的项目
复制 trans_sale 我的项目,并重命名为 trans_sal_aspectj。在此基础上批改。
Step2:maven 依赖 pom.xml
新退出 aspectj 的依赖坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
Step3:在容器中增加事务管理器
Step4:配置事务告诉
为事务告诉设置相干属性。用于指定要将事务以什么形式织入给哪些办法。
例如,利用到 buy 办法上的事务要求是必须的,且当 buy 办法产生异样后要回滚业务。
Step5:配置增强器
指定将配置好的事务告诉,织入给谁。
Step6:批改测试类
测试类中要从容器中获取的是指标对象。