spring学习——声明式事务

简介: spring学习——声明式事务

事务概述

  1. 在 JavaEE 企业级开发的应用领域,为了保证数据的完整性和一致性,必须引入数据库事务的概念,所以事务管理是企业级应用程序开发中必不可少的技术。
  2. 事务 :是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
  3. 事务的四个关键属性(ACID)

原子性(atomicity):

“原子”的本意是“不可再分”,事务的原子性表现为一个事务中涉及到的多个操作在逻辑上缺一不可。事务的原子性要求事务中的所有操作要么都执行,要么都不执行。

一致性(consistency):

“一致”指的是数据的一致,具体是指:所有数据都处于满足业务规则的一致性状态。

一致性原则要求:一个事务中不管涉及到多少个操作,都必须保证事务执行之前数据是正确的,事务执行之后数据仍然是正确的。如果一个事务在执行的过程中, 其中某一个或某几个操作失败了,则必须将其他所有操作撤销,将数据恢复到事务执行之前的状态,这就是回滚

隔离性(isolation):

在应用程序实际运行过程中,事务往往是并发执行的,所以很有可能有许多事务同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

隔离性原则要求多个事务在并发执行过程中不会互相干扰

持久性(durability):

持久性原则要求事务执行完成后,对数据的修改永久的保存下来, 不会因各种系统错误或其他意外情况而受到影响。通常情况下,事务对数据的修改应该被写入到持久化存储器中。


Spring 事务管理

编程式事务管理

  1. 使用原生的 JDBC API 进行事务管理
    ①获取数据库连接 Connection 对象
    ②取消事务的自动提交
    ③执行操作
    ④正常完成操作时手动提交事务
    ⑤执行失败时回滚事务
    ⑥关闭相关资源

声明式事务管理

  • 大多数情况下声明式事务比编程式事务管理更好:
    它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
  • 事务管理代码的固定模式作为一种横切关注点,可以通过 AOP 方法模块化,进而借助 Spring AOP 框架实现声明式事务管理。
  • Spring 在不同的事务管理 API 之上定义了一个抽象层,通过配置的方式使其生效,从而 让应用程序开发人员不必了解事务管理 API 的底层实现细节,就可以使用 Spring 的事务管理机制。
  • Spring 既支持编程式事务管理,也支持声明式的事务管理。

Spring 提供的事务管理器

  • Spring 从不同的事务管理 API 中抽象出了一整套事务管理机制,让事务管理代码从特定的事务技术中独立出来。开发人员通过配置的方式进行事务管理,而不必了解其底层是如何实现的。
  • Spring 的核心事务管理抽象是PlatformTransactionManager。
    它为事务管理封装了一组独立于技术的方法。无论使用 Spring 的哪种事务管理策略(编程式或声明式),事务管理器都是必须的。
  • 事务管理器可以以普通的 bean 的形式声明在 Spring IOC 容器中。

事务管理器的主要实现

  1. DataSourceTransactionManager
    在应用程序中只需要处理一个数据源,通过 JDBC 存取。
  2. JtaTransactionManager
    在 JavaEE 应用服务器上用 JTA(Java Transaction API)进行事务管理
  3. HibernateTransactionManager
    用 Hibernate 框架存取数据库

测试数据准备

需求

数据库表

CREATE TABLE book (
isbn VARCHAR (50) PRIMARY KEY, 
book_name VARCHAR (100), 
price INT 
) ; 
CREATE TABLE book_stock ( 
isbn VARCHAR (50) PRIMARY KEY, 
stock INT, 
CHECK (stock > 0) 
) ; 
CREATE TABLE account ( 
username VARCHAR (50) PRIMARY KEY, 
balance INT, 
CHECK (balance > 0) 
) ; 
INSERT INTO account (`username`,`balance`) VALUES ('Tom',100000); 
INSERT INTO account (`username`,`balance`) VALUES ('Jerry',150000); 
INSERT INTO book (`isbn`,`book_name`,`price`) VALUES ('ISBN-001','book01',100); 
INSERT INTO book (`isbn`,`book_name`,`price`) VALUES ('ISBN-002','book02',200); 
INSERT INTO book (`isbn`,`book_name`,`price`) VALUES ('ISBN-003','book03',300); 
INSERT INTO book (`isbn`,`book_name`,`price`) VALUES ('ISBN-004','book04',400); 
INSERT INTO book (`isbn`,`book_name`,`price`) VALUES ('ISBN-005','book05',500); 
INSERT INTO book_stock (`isbn`,`stock`) VALUES ('ISBN-001',1000); 
INSERT INTO book_stock (`isbn`,`stock`) VALUES ('ISBN-002',2000);
INSERT INTO book_stock (`isbn`,`stock`) VALUES ('ISBN-003',3000); 
INSERT INTO book_stock (`isbn`,`stock`) VALUES ('ISBN-004',4000); 
INSERT INTO book_stock (`isbn`,`stock`) VALUES ('ISBN-005',5000);

初步实现

1) 配置文件

<!-- 配置事务管理器 --> 
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
  <property name="dataSource" ref="dataSource"/> 
</bean> 
<!-- 启用事务注解 --> 
<tx:annotation-driven transaction-manager="transactionManager"/>

2) 在需要进行事务控制的方法上加注解 @Transactional

例如:

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
    @Override
    public Users findUsersById(String loginId) {}

事务的传播行为

简介

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。

  • 例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
  • 事务的传播行为可以由传播属性指定。
  • 事务传播属性可以在@Transactional 注解的 propagation 属性中定义。

Spring 定义了 7 种类传播行为:

测试

  1. . 说明
    ①REQUIRED 传播行为 当 bookService 的 purchase()方法被另一个事务方法 checkout()调用时,它默认会在 现有的事务内运行。这个默认的传播行为就是 REQUIRED。因此在 checkout()方法的开 始和终止边界内只有一个事务。这个事务只在 checkout()方法结束的时候被提交,结果用户一本书都买不了。

    ②. REQUIRES_NEW 传播行为 表示该方法必须启动一个新事务,并在自己的事务内运行。如果有事务在运行,就 应该先挂起它。

补充

在 Spring 2.x 事务通知中,可以像下面这样在tx:method元素中设定传播事务属性。


事务的隔离级别

数据库事务并发问题

假设现在有两个事务:Transaction01 和 Transaction02 并发执行。

  1. 脏读
    ①Transaction01 将某条记录的 AGE 值从 20 修改为 30。
    ②Transaction02 读取了 Transaction01 更新后的值:30。
    ③Transaction01 回滚,AGE 值恢复到了 20。
    ④Transaction02 读取到的 30 就是一个无效的值。
  2. 不可重复读
    ①Transaction01 读取了 AGE 值为 20。
    ②Transaction02 将 AGE 值修改为 30。
    ③Transaction01 再次读取 AGE 值为 30,和第一次读取不一致。
  3. 幻读
    ①Transaction01 读取了 STUDENT 表中的一部分数据。
    ②Transaction02 向 STUDENT 表中插入了新的行。
    ③Transaction01 读取了 STUDENT 表时,多出了一些行。

隔离级别

数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并 发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL 标准中规定了多种事务隔离级 别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

  1. 读未提交:READ UNCOMMITTED 允许 Transaction01 读取 Transaction02 未提交的修改。
  2. 读已提交:READ COMMITTED 要求 Transaction01 只能读取 Transaction02 已提交的修改。
  3. 可重复读:REPEATABLE READ 确保 Transaction01 可以多次从一个字段中读取到相同的值,即 Transaction01 执行 期间禁止其它事务对这个字段进行更新。
  4. 串行化:SERIALIZABLE 确保 Transaction01 可以多次从一个表中读取到相同的行,在 Transaction01 执行期 间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性 能十分低下。
  5. 各个隔离级别解决并发问题的能力见下表
  6. 各种数据库产品对事务隔离级别的支持程度

在 Spring 中指定事务隔离级别

  1. 注解
    用@Transactional 注解声明式地管理事务时可以在@Transactional 的 isolation 属性 中设置隔离级别
  2. XML
    在 Spring 2.x 事务通知中,可以在tx:method元素中指定隔离级别

触发事务回滚的异常

默认情况

捕获到 RuntimeException 或 Error 时回滚,而捕获到编译时异常不回滚。

设置途经

  1. 注解@Transactional 注解
    ① rollbackFor 属性:指定遇到时必须进行回滚的异常类型,可以为多个
    ② noRollbackFor 属性:指定遇到时不回滚的异常类型,可以为多个
  2. XML 在 Spring 2.x 事务通知中,可以在tx:method元素中指定回滚规则。如果有不止 一种异常则用逗号分隔。

事务的超时和只读属性

简介

由于事务可以在行和表上获得锁,因此长事务会占用资源,并对整体性能产生影响。 如果一个事务只读取数据但不做修改,数据库引擎可以对这个事务进行优化。 超时事务属性:事务在强制回滚之前可以保持多久。这样可以防止长期运行的事务占用资源。只读事务属性: 表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化 事务。

设置

  1. 注解@Transaction 注解
  2. XML 在 Spring 2.x 事务通知中,超时和只读属性可以在< tx:method >元素中进行指定

基于 XML 文档的声明式事务配置

<!-- 配置事务切面 --> 
<aop:config>
<aop:pointcut expression="execution(*com.atguigu.tx.component.service.BookShopServiceImpl.purchase(..))" id="txPointCut"/> 
  <!-- 将切入点表达式和事务属性配置关联到一起 --> 
  <aop:advisor advice-ref="myTx" pointcut-ref="txPointCut"/> 
  </aop:config> 
  <!-- 配置基于 XML 的声明式事务 --> 
  <tx:advice id="myTx" transaction-manager="transactionManager"> 
  <tx:attributes> 
  <!-- 设置具体方法的事务属性 --> 
  <tx:method name="find*" read-only="true"/> 
  <tx:method name="get*" read-only="true"/> 
  <tx:method name="purchase" isolation="READ_COMMITTED" no-rollback-for="java.lang.ArithmeticException,java.lang.NullPointerException" propagation="REQUIRES_NEW" read-only="false" timeout="10"/> 
</tx:attributes> 
</tx:advice>


相关文章
|
2月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
6天前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
|
9天前
|
Java 测试技术 数据库
Spring事务传播机制(最全示例)
在使用Spring框架进行开发时,`service`层的方法通常带有事务。本文详细探讨了Spring事务在多个方法间的传播机制,主要包括7种传播类型:`REQUIRED`、`SUPPORTS`、`MANDATORY`、`REQUIRES_NEW`、`NOT_SUPPORTED`、`NEVER` 和 `NESTED`。通过示例代码和数据库插入测试,逐一展示了每种类型的运作方式。例如,`REQUIRED`表示如果当前存在事务则加入该事务,否则创建新事务;`SUPPORTS`表示如果当前存在事务则加入,否则以非事务方式执行;`MANDATORY`表示必须在现有事务中运行,否则抛出异常;
42 4
Spring事务传播机制(最全示例)
|
5天前
|
Java Spring
Spring 事务传播机制是什么?
Spring 事务传播机制是什么?
14 4
|
2月前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
60 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
|
2月前
|
缓存 前端开发 JavaScript
前后端分离 SpringBoot+Vue商城买卖系统通杀版本。大家可以参考学习一下
这篇文章介绍了一个使用SpringBoot+Vue开发的前后端分离商城系统,包括技术架构、开发环境、实现的功能以及项目截图,并展示了普通用户和商家端的功能界面。
前后端分离 SpringBoot+Vue商城买卖系统通杀版本。大家可以参考学习一下
|
2月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
2月前
|
前端开发 Java 数据库连接
一天十道Java面试题----第五天(spring的事务传播机制------>mybatis的优缺点)
这篇文章总结了Java面试中的十个问题,包括Spring事务传播机制、Spring事务失效条件、Bean自动装配方式、Spring、Spring MVC和Spring Boot的区别、Spring MVC的工作流程和主要组件、Spring Boot的自动配置原理和Starter概念、嵌入式服务器的使用原因,以及MyBatis的优缺点。
|
2月前
|
设计模式 Java 程序员
学习 Spring 源码的意义是什么呢?
研究Spring源码能深化框架理解,提升代码分析与设计能力,助您掌握设计模式及最佳实践,增强解决问题的效率,促进职业生涯发展,并激发技术热情。选择稳定版本,从核心模块开始,结合实际项目并参与社区,让学习之旅既充实又具乐趣。
|
6天前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
下一篇
无影云桌面