Spring事务( Transaction )

事务的概念

事务是一些sql语句的集合,作为一个整体执行,一起成功或者一起失败。

使用事务的时机

一个操作需要多天sql语句一起完成才能成功

程序中事务在哪里说明

加在业务类的方法上面(public方法上面),表示业务方法执行时,需要事务的支持。

不同的事务管理器

不同的数据库访问技术,处理事务是不同的

  1. 使用jdbc 访问数据库,事务处理

    public void updateAccount(){
    Connection con = .....;
    con.setAutoCommit(false);
    state.insert();
    state.update();
    state.commit();
    con.setAutoCommit(true);
    }
  2. MyBatis执行数据库,处理事务

    public void updateAccount(){
    SqlSession sqlSession = SqlSessionFactory.openSession(false);
    try{
    sqlSession.insert(...);
    sqlSession.update(...);
    sqlSession.commit();
    }catch(Exception e){
    sqlSession.rollback();
    }
    }

spring统一管理事务,把不同的数据库访问技术的事务处理统一起来

使用spring的事务管理器,管理不同数据库访问技术的事务处理。开发人员只需要掌握spring的事务处理一个方案,就可以实现使用不同数据库访问技术的事务管理。

尽管事务面向的是spring,有spring管理事务,做事务提交和回滚。

spring事务管理器

spring框架使用事务管理器对象,管理所有的事务。

事务管理器接口: PlatFormTransactionManager

​ 作用 :定义了事务的操作,主要是commit() , rollback()

事务管理器有很多的实现类:一种数据库访问计数有一个实现类。由实现类具体完成事务的提交,回滚。

这意味着:JDBC或者MyBatis访问数据库有自己的事务管理实现类:DataSourceTransactionManager

​ hibernate框架,他的事务管理器实现类:HibernateTransactionManager

事务管理器的工作方式

spring集中统一管理事务,分配管理事务给具体的事务管理器对象。

事务提交和回滚的时机

当业务正常执行的时候,没有异常,事务是提交的。如果业务代码中出现了运行时异常,事务会发生回滚。

异常的分类:

  • Error : 错误,回滚事务
  • Exception:
    • 运行时异常:RuntimeException和他的子类都是运行时异常,在程序执行过程中抛出的异常
    • 受查异常:在编写代码时需要处理的异常(编译都无法通过),会提交事务。

方法抛出运行时异常事务回滚,其他的情况都是执行事务。

spring事务管理的实现方式:AOP中的环绕通知

环绕通知:在目标方法的前后都可以增加功能,不需要修改代码。

// spring给业务方法在执行时,增加事务的切面功能(一下为大致的实现步骤,不是真正的执行代码)
@Around("execution(* com.wang.*.*(..))")
public Object myAround(ProceedingJoinPoint pjp){
try{
PlatformTransactionManager.beginTransaction(); // 使用spring的事务管理器,开启事务
pjp.proceed(); // 执行目标方法
PlatformTransactionManager.commit(); // 业务方法正常执行,事务提交
}catch(Exception e){
PlatformTransactionManager.roolback(); // 业务方法非正常执行,事务回滚
}
}

事务定义接口(TransactionDefinition )

事务定义接口TransactionDefinition中定义了事务描述相关的三类常量:事务隔离级别,事务传播行为,事务默认超时时限,及他们的操作。

给业务方法说明事务的属性。

隔离级别

定义

控制事务之间的影响速度

具体值
  • DEFAULT:采用DB默认的事务隔离级别。Mysql的默认为REPEATABLE_READ,Oracle默认为READ_COMMITTED
  • READ_UNCOMMITTED:读未提交。未解决任何并发问题
  • READ_COMMITTER:读已提交。解决脏读,存在不可重复读和幻读
  • REPETABLE_READ:可重复读。解决脏读,不可重复读,存在幻读
  • SERIALIZABLE:串行化。不存在并发问题。

事务超时时间

以秒为单位,整数值,默认为-1

超时时间:表示一个业务方法最长的执行时间,到达时间没有执行完毕,spring会回滚事务。

传播行为

传播行为有7个值

定义:业务方法在调用的时候,事务在方法之间的传递和使用。

使用传播行为,表示方法有无事务。

  • PROPAGATION_REQUIRED

  • PROPAGATION_REQUIRES_NEW

  • PROPAGATION_SUPPORTS

    以上三个需要掌握

  • PROPAGATION_MANDATORY

  • PROPAGATION_NESTED

  • PROPAGATION_NEVER

  • PROPAGATION_NOT_SUPPORTED

  1. PROPAGATION_REQUIRED:spring默认传播行为,方法在调用的时候,如果存在事务就是用当前的事务,如果没有事务,就新建一个事务,方法在新事务中执行。
  2. PROPAGATION_SUPPORTS: 方法有事务可以正常执行,没有事务也可以正常执行。(查询操作)
  3. PROPAGATION_REQUIRES_NEW:方法需要一个新事务。如果调用方法的时候,存在一个事务,则原来的事务暂停,知道新事务执行完毕。如果方法调用的时候,没有事务,则新建一个事务,在新事务中执行代码。

spring框架使用自己的注解@Transactional控制事务

@Transactional注解,使用注解的属性控制事务(隔离级别,传播行为,超时)

​ 其中的属性:

  • propagation:事务的传播行为,他使用的Propagation类的枚举值,例如:Propagation.REQUIRED;
  • isolation:表示隔离级别,使用Isolation类的枚举值,表示隔离级别,默认是:Ioslation.DEFAULT;
  • readOnly:boolean类型的值,表示数据库操作是不是只读的,默认为false
  • timeout:事务超时,默认是-1,整数值,单位是秒,例如:timeout=20;
  • rollbackFor:表示回滚的异常类列表,他的值是一个数组,每个值是异常类型的class。
  • rollbackForClassName:表示回滚的异常类列表,是String类型的值
  • noRollbackFor:不需要回滚的异常类列表,是class类型的
  • noRollbackForClassName:不需要回滚的异常类列表,是String类型的值

该注解放置的位置:

  1. 在业务方法上面,实在public方法上面(大多数)
  2. 在类的上面(几乎见不到)

注解的使用步骤

  1. 在spring配置文件中,声明事务的内容;

    声明事务管理器,说明使用哪个事务管理器对象;

    声明使用注解管理事务,开启注解驱动

  2. 在类的源代码中,加入@Transactional

事务的控制模式:

  1. 编程式,在代码中编程控制事务
  2. 声明式事务,不用编码
步骤一:
<!--声明事务管理器(连接到数据库,做事务提交,事务回滚)-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<!--指定数据源-->
<property name="dataSource" ref="myDataSource"/>
</bean> <!--开启事务注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--最后导入的包是以tx结尾-->
步骤二:

在具体的方法上加上@Transactional注解

	@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
timeout = 20,
rollbackFor = {NullPointerException.class}
)
@Override
public void buy(Integer goodId, Integer amount) throws Exception {
System.out.println("buy方法的执行");
Sale sale = new Sale();
sale.setGid(goodId);
sale.setNums(amount);
// 生成销售记录
saleDao.insertSale(sale);
// 查询商品
Good good = goodDao.selectById(goodId);
if (good == null){
throw new Exception("商品不存在");
}else if (good.getAmount() < amount){
throw new Exception("库存不足");
}
// 更新库存
Good good1 = new Good();
good1.setId(goodId);
good1.setAmount(amount);
goodDao.updateGood(good1);
System.out.println("buy方法的完成");
}
rollbackFor说明
  1. 框架首先检查方法抛出的异常是不是在rollbackFor数组中,如果在一定会发生回滚;
  2. 如果方法抛出的异常不在rollbackFor数组中,框架会继续检查抛出的异常是不是RuntimrException,如果是RuntimeException,一定会发生回滚。

使用rollbackFor可以实现发生受检查异常时让其发生回滚。

注解的使用特点

直接使用@Transactional会使用默认值

  • spring框架自己提供的事务控制
  • 适合中小型项目,注解都放置在了源代码中,不利于优化
  • 使用方便效率高

使用Aspectj框架在spring配置文件中,声明事务控制

使用aspectj的aop,声明事务控制叫做声明式事务

使用步骤

  1. 加入spring-aspectj的依赖
  2. 在spring的配置文件声明事务属性
    • 声明事务管理器
    • 声明业务方法需要的事务属性
    • 声明切入点表达式
步骤

基本上是模板化的方法

<!--声明式事务-->
<!--1.声明事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager2">
<property name="dataSource" ref="myDataSource"/>
</bean> <!--2.声明业务方法的事务属性(隔离级别,传播行为,超时)
id:给业务方法配置事务段代码起个名字,唯一值
transaction-manager:事务管理器的id
-->
<tx:advice id="serviceAdvice" transaction-manager="transactionManager2">
<!--给具体的业务方法增加事务的说明-->
<tx:attributes>
<!-- 给具体的业务方法,说明他需要的事务属性
name:业务方法名称,配置name的值 1.业务方法的名称(类中的某一个方法) 2.带有部分通配符的方法名称 3.使用*
propagation:指定传播行为
isolation:隔离级别
read-only:是否只读,默认为false
timeout:超时时间
rollback-for:指定回滚的异常类列表,使用的异常类的全限定名称(多个异常时用都好分割)
-->
<tx:method name="buy"
isolation="DEFAULT"
propagation="REQUIRED"
timeout="20"
rollback-for="java.lang.NullPointerException"
/> <!--在业务方法有命名规则的时候,可以对一些方法使用事务-->
<tx:method name="add*" propagation="REQUIRED" timeout="20" isolation="DEFAULT"/>
<tx:method name="delete*" propagation="REQUIRED" timeout="20" isolation="DEFAULT"/>
<!--以上方法以外的-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--通过上述方法的声明,但是我们并不知道是哪个类的方法,让上述声明生效的方法:切入点表达式-->
<!--声明切入点表达式:表示哪些包中的哪些类的方法参与事务-->
<aop:config>
<!--声明切入点表达式
expression:切入点表达式,表示哪些类中的哪些方法要参与事务
id:切入点表达式的名称,唯一值
-->
<aop:pointcut id="servicePointCut" expression="execution(* *..service..*.*(..))"/>
<!-- 关联切入点表达式和事务的通知-->
<aop:advisor advice-ref="serviceAdvice" pointcut-ref="servicePointCut"/>
</aop:config>
优缺点
  • 缺点:理解难,配置复杂

  • 优点:代码和事务分开。控制事务源代码不用修改。

    ​ 能快速的了解和掌握项目的全部事务。适合大型项目。

spring事务详解(基于注解和声明的两种实现方式)的更多相关文章

  1. spring事务详解(二)简单样例

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  2. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  3. spring事务详解(一)初探事务

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 引子 很多 ...

  4. spring事务详解(五)总结提高

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.概念 ...

  5. spring事务详解(四)测试验证

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  6. spring事务详解(二)实例

    在Spring中,事务有两种实现方式: 编程式事务管理: 编程式事务管理使用底层源码可实现更细粒度的事务控制.spring推荐使用TransactionTemplate,典型的模板模式. 申明式事务管 ...

  7. Spring、Spring事务详解;使用XML配置事务

    @Transactional可以设置以下参数: @Transactional(readOnly=false) // 指定事务是否只读的 true/false @Transactional(rollba ...

  8. 【转】Spring事务详解

    1.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交,那在没有Spring帮我们管理事务 ...

  9. Spring 事务详解

    实现购买股票案例: 一.引入JAR文件: 二.开始搭建分层架构---创建账户(Account)和股票(Stock)实体类 Account: ? 1 2 3 4 5 6 7 8 9 10 11 12 1 ...

随机推荐

  1. LVS+Keepalived 高可用群集部署

    LVS+Keepalived 高可用群集部署 1.LVS+Keepalived 高可用群集概述 2.LVS+Keepalived高可用群集部署 1.LVS+Keepalived 高可用群集概述: LV ...

  2. docker基础——3.存储卷

    把宿主机的目录或文件链接到容器的目录或文件,可以避免写时复制对高I/O操作的影响,也避免容器销毁时数据丢失. 1. 只指定容器的目录位置,-v docker run -it --name bbox1 ...

  3. 手写RPC框架(六)整合Netty

    手写RPC框架(六)整合Netty Netty简介: Netty是一个基于NIO的,提供异步,事件驱动的网络应用工具,具有高性能高可靠性等特点. 使用传统的Socket来进行网络通信,服务端每一个连接 ...

  4. CVE-2021-1732 LPE漏洞分析

    概述 CVE-2021-1732是一个发生在windows内核win32kfull模块的LPE漏洞,并且由于创建窗口时调用win32kfull!xxxCreateWindowEx过程中会进行用户模式回 ...

  5. Session是什么?它与Cookie有什么区别?

    你好,是我琉忆. 今天我们讲一讲Session与Cookie的区别 1.Session对象 上一节简单介绍了Cookie,接下来简单介绍Session.Session和Cookie都是会话管理技术的一 ...

  6. Dubbo源码剖析一之整体架构设计

    Dubbo基础二之架构及处理流程概述 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中进行Dubbo职能上的简单介绍,下面就其内部进行详细探究: 1.Dubbo调用关系 这个图是不是很熟 ...

  7. Banmabanma的writeup

    大家好,好久不见,前段时间忙于应付网课和作业,还有这恐怖的疫情,差点就嗝屁了......     好了,接下来我们步入正题,这次我为大家带来攻防世界misc部分Banmabanma的writeup. ...

  8. 年底获奖人太多?奖状可以用Smartbi电子表格这么做!

    又到一年年终时,你的年终奖到手了吗?奖金没领到,发个奖状压压惊 今天给大家分享年终奖相关的年终奖状的批量套打功能,保证你的奖状及时到手! 示例说明 现有多个人员的奖励需要通知,需要生成可翻页的奖状.并 ...

  9. 字符串压缩(一)之ZSTD

    前言 最近项目上有大量的字符串数据需要存储到内存,并且需要储存至一定时间,于是自然而然的想到了使用字符串压缩算法对"源串"进行压缩存储.由此触发了对一些优秀压缩算法的调研. 字符串 ...

  10. random_sample() takes at most 1 positional argument (2 given)

    是random模块下的sample函数,而不是np.random.