Spring5.0源码学习系列之事务管理概述(十一)

Spring5.0源码学习系列之事务管理概述(十一),在学习事务管理的源码之前,需要对事务的基本理论比较熟悉,所以本章节会对事务管理的基本理论进行描述

1、什么是事务?

事务就是一组原子性的SQL操作,或者说一个独立的工作单元。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)

注意:Spring的事务支持是基于数据库事务的,在MySQL数据库中目前只有InnoDB或者NDB集群引擎才支持,MySQL5.0之前的默认MyISAM存储引擎是不支持事务的

2、事务的ACID特性

ACID其实是事务特性的英文首字母缩写,具体含义是:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)

  • 原子性(atomicity):事务是一个原子操作,由一系列动作组成。整个事务中的所有操作要么全部提交成功,要么全部失败回滚;
  • 一致性(consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态,执行事务前后,数据保持一致;
  • 隔离性(isolation): 因为有多个事务处理同个数据的情况,因此每个事务都应该与其他事务隔离开来,防止数据脏读、不可重复读等等情况;
  • 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢;

3、什么是脏读、不可重复读、幻读?

  • 脏读
    在A事务修改数据,提交事务之前,另外一个B事务读取了A事务未提交事务之前的数据,这种情况称之为脏读(Dirty Read)
  • 不可重复读
    一个A事务在读取某些数据,第1次读取出来的数据结果和第2次读取出来的不一致,因为在两次数据读取期间,另外的事务对数据进行了更改
  • 幻读
    幻读和不可重复读是很类似的,不同的地方在于幻读侧重于事务对数据的删除或者新增,都是因为在两次数据读取期间,因为另外事务对数据的删除还是新增,导致第2次读取的数据和第1次不一致

4、Spring事务管理核心接口

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

在这里插入图片描述

在这里插入图片描述

5、事务隔离级别

定义:事务的隔离级别定义了一个事务可能受其他并发事务影响的程度。隔离级别可以不同程度的解决脏读、不可重复读、幻读。

隔离级别描述脏读不可重复读幻读
ISOLATION_DEFAULT使用后端数据库默认的隔离级别,默认的为Repeatable read (可重复读)
ISOLATION_READ_UNCOMMITTED不可提交读,允许读取尚未提交事务的数据,可能会导致脏读、不可重复读、幻读
ISOLATION_READ_COMMITTED提交读,读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
ISOLATION_REPEATABLE_READ可重复读,可以阻止脏读和不可重复读,但幻读仍有可能发生
ISOLATION_SERIALIZABLE串行化,这种级别是最高级别,服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读

6、事务的传播行为

事务传播行为描述
PROPAGATION_REQUIRED必须,默认值。如果A有事务,B将使用该事务;如果A没有事务,B将创建一个新的事务
PROPAGATION_SUPPORTS支持。如果A有事务,B将使用该事务;如果A没有事务,B将以非事务执行
PROPAGATION_MANDATORY强制。A如果有事务,B将使用该事务;如果A没有事务,B将抛异常
PROPAGATION_REQUIRES_NEW必须新的。如果A有事务,将A的事务挂起,B创建一个新的事务;如果A没有事务,B创建一个新的事务。
PROPAGATION_NOT_SUPPORTED不支持。如果A有事务,将A的事务挂起,B将以非事务执行;如果A没有事务,B将以非事务执行。
PROPAGATION_NEVER从不。如果A有事务,B将抛异常;如果A没有事务,B将以非事务执行
PROPAGATION_NESTED嵌套。A和B底层采用保存点机制,形成嵌套事务。

7、事务管理其它属性

前面介绍了事务管理的隔离级别和传播行为这两个重要的属性,接着介绍一下事务的其它属性

  • 事务超时属性
    事务超时,属性值是timeout,指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。以 int 的值来表示超时时间,其单位是秒,默认值为-1。
  • 事务只读属性
    属性值readOnly,对于只有读取数据查询的事务,可以指定事务类型为 readonly,即只读事务。只读事务不涉及数据的修改,数据库会提供一些优化手段,所以对于业务很明确的接口,可以适当加上只读属性
  • 事务回滚规则
    属性值rollbackFor,默认情况下,事务只有遇到运行期异常(RuntimeException 的子类)时才会回滚,Error 也会导致事务回滚
属性名说明
propagation事务的传播行为,默认值为 REQUIRED
isolation事务的隔离级别,默认值采用 DEFAULT
timeout事务的超时时间,默认值-1,表示不会超时,如果设置其它值,超过该时间限制但事务还没有完成,则自动回滚事务
readOnly指定事务为只读事务,默认值false
rollbackFor指定能够触发事务回滚的异常类型,并且可以指定多个异常类型。

8、Spring事务实现方式

Spring事务代码实现方式有两种,一种是编程式事务,一种是声明式事务。所谓编程式事务,是指通过Spring框架提供的TransactionTemplate或者直接使用底层的PlatformTransactionManager。声明式事务,依赖Spring AOP,配置文件中做相关的事务规则声明或者直接使用@Transactional注解

下面给出一个典型的转账汇款例子,先不用事务的方式实现,接着使用编程式事务和声明式事务进行事务管理

package com.example.springframework.dao.impl;

import com.example.springframework.dao.AccountDao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
 * <pre>
 *      AccountDaoImpl
 * </pre>
 *
 * <pre>
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2021/03/25 15:51  修改内容:
 * </pre>
 */
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Override
    public void out(String outer, int money) {
        super.getJdbcTemplate().update("update account set money = money - ? where usercode=?",money,outer);
    }

    @Override
    public void in(String inner, int money) {
        super.getJdbcTemplate().update("update account set money = money + ? where usercode = ?",money , inner);
    }
}

package com.example.springframework.service.impl;

import com.example.springframework.dao.AccountDao;
import com.example.springframework.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Service;


/**
 * <pre>
 *      AccountServiceImpl
 * </pre>
 *
 * <pre>
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2021/03/25 15:55  修改内容:
 * </pre>
 */
@Service
public class AccountServiceImpl extends JdbcDaoSupport implements AccountService {

    AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(final String outer,final String inner,final int money){
        accountDao.out(outer , money);
        // exception
        // int i = 1 / 0;
        accountDao.in(inner , money);
    }
    
}

代码例子看起来是挺正常的,不过假如在accountDao.out(outer , money);accountDao.in(inner , money);两个事务执行期间,发生异常,这时会怎么样?效果如图:Jack的账号已经转账成功,转了1000,不过Tom并没有收到汇款,这种情况在实际生活中肯定是不允许的,所以需要使用事务进行管理
在这里插入图片描述

9、Spring编程式事务

Spring编程式事务实现,通过Spring框架提供的TransactionTemplate或者直接使用底层的PlatformTransactionManager

  • 使用TransactionTemplate的方式
private AccountDao accountDao;
private TransactionTemplate transactionTemplate;

public void setAccountDao(AccountDao accountDao) {
    this.accountDao = accountDao;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
    this.transactionTemplate = transactionTemplate;
}

@Override
public void transfer(final String outer,final String inner,final int money){
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            accountDao.out(outer , money);
            // exception
            int i = 1 / 0;
            accountDao.in(inner , money);
        }
    });
}
  • 使用PlatformTransactionManager的方式
private AccountDao accountDao;

public void setAccountDao(AccountDao accountDao) {
    this.accountDao = accountDao;
}

@Override
public void transferTrans(String outer, String inner, int money) {
    DataSourceTransactionManager dataSourceTransactionManager =
            new DataSourceTransactionManager();
    // 设置数据源
    dataSourceTransactionManager.setDataSource(super.getJdbcTemplate().getDataSource());
    DefaultTransactionDefinition transDef = new DefaultTransactionDefinition();
    // 设置传播行为属性
    transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
    TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef);
    try {
        accountDao.out(outer , money);
        // exception
        int i = 1 / 0;
        accountDao.in(inner , money);
        //commit
        dataSourceTransactionManager.commit(status);
    } catch (Exception e) {
        // rollback
        dataSourceTransactionManager.rollback(status);
    }
}

10、Spring声明式事务

Spring声明式事务依赖于Spring AOP,通过配置文件中做相关的事务规则声明或者直接使用@Transactional注解

  • AOP规则声明方式
    这种方式在 applicationContext.xml 文件中配置 aop 自动生成代理,进行事务管理
<?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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="minstone"></property>
    </bean>

    <bean id="accountDao" class="com.example.springframework.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="accountService" class="com.example.springframework.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>
	<!-- 事务管理器配置 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- xml配置事务 propagation 传播行为isolation 隔离级别-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>
	
	<!-- 配置所有的Service方法都支持事务-->
    <aop:config>
     <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.springframework.service..*.*(..))"/>
 </aop:config>

  
</beans>
  • 使用AOP注解方式
    在applicationContext.xml 配置事务管理器,将并事务管理器交予spring,在目标类或目标方法添加注解即可 @Transactional, proxy-target-class设置为 true : 底层强制使用cglib 代理

注意点:@Transactional只能用于public方法,不管是加上类上还是方法上

<!-- 事务管理器配置 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

<!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务  -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>

通过上述管理之后,一旦发生异常,两边都会进行事务回滚,没有异常,正常提交事务
在这里插入图片描述

本文例子代码可以在github找到下载链接

smileNicky CSDN认证博客专家 分布式 Java Spring
java程序员,软件工程专业,专注于sql调优,SpringBoot,spring框架学习,个人邮箱nickypm@foxmail.com,公众号nickymp
已标记关键词 清除标记
相关推荐
陈开雄 Spring+3.x企业应用开发实战光盘源码 !!!!压缩包的jar包太多,太大无法上传,请谅解,需要的可以联系我 QQ:349721489 第1章:对Spring框架进行宏观性的概述,力图使读者建立起对Spring整体性的认识。   第2章:通过一个简单的例子展现开发Spring Web应用的整体过程,通过这个实例,读者可以快速跨入Spring Web应用的世界。   第3章:讲解Spring IoC容器的知识,通过具体的实例详细地讲解IoC概念。同时,对Spring框架的三个最重要的框架级接口进行了剖析,并对Bean的生命周期进行讲解。   第4章:讲解如何在Spring配置文件中使用Spring 3.0的Schema格式配置Bean的内容,并对各个配置项的意义进行了深入的说明。   第5章:对Spring容器进行解构,从内部探究Spring容器的体系结构和运行流程。此外,我们还将对Spring容器一些高级主题进行深入的阐述。   第6章:我们从Spring AOP的底层实现技术入手,一步步深入到Spring AOP的内核中,分析它的底层结构和具体实现。   第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、使用注解进行配置等内容。   第8章:介绍了Spring所提供的DAO封装层,这包括Spring DAO的异常体系、数据访问模板等内容。   第9章:介绍了Spring事务管理的工作机制,通过XML、注解等方式进行事务管理配置,同时还讲解了JTA事务配置知识。   第10章:对实际应用中Spring事务管理各种疑难问题进行透彻的剖析,让读者对Spring事务管理不再有云遮雾罩的感觉。   第11章:讲解了如何使用Spring JDBC进行数据访问操作,我们还重点讲述了LOB字段处理、主键产生和获取等难点知识。   第12章:讲解了如何在Spring中集成Hibernate、myBatis等数据访问框架,同时,读者还将学习到ORM框架的混用和DAO层设计的知识。   第13章:本章重点对在Spring中如何使用Quartz进行任务调度进行了讲解,同时还涉及了使用JDK Timer和JDK 5.0执行器的知识。   第14章:介绍Spring 3.0新增的OXM模块,同时对XML技术进行了整体的了解。   第15章:对Spring MVC框架进行详细介绍,对REST风格编程方式进行重点讲解,同时还对Spring 3.0的校验和格式化框架如果和Spring MVC整合进行讲解。   第16章:有别于一般书籍的单元测试内容,本书以当前最具实战的JUnit4+Unitils+ Mockito复合测试框架对如何测试数据库、Web的应用进行了深入的讲解。   第17章:以一个实际的项目为蓝本,带领读者从项目需求分析、项目设计、代码开发、单元测试直到应用部署经历整个实际项目的整体开发过程。
第1章:对Spring框架进行宏观性的概述,力图使读者建立起对Spring整体性的认识。   第2章:通过一个简单的例子展现开发Spring Web应用的整体过程,通过这个实例,读者可以快速跨入Spring Web应用的世界。   第3章:讲解Spring IoC容器的知识,通过具体的实例详细地讲解IoC概念。同时,对Spring框架的三个最重要的框架级接口进行了剖析,并对Bean的生命周期进行讲解。   第4章:讲解如何在Spring配置文件中使用Spring 3.0的Schema格式配置Bean的内容,并对各个配置项的意义进行了深入的说明。   第5章:对Spring容器进行解构,从内部探究Spring容器的体系结构和运行流程。此外,我们还将对Spring容器一些高级主题进行深入的阐述。   第6章:我们从Spring AOP的底层实现技术入手,一步步深入到Spring AOP的内核中,分析它的底层结构和具体实现。   第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、使用注解进行配置等内容。   第8章:介绍了Spring所提供的DAO封装层,这包括Spring DAO的异常体系、数据访问模板等内容。   第9章:介绍了Spring事务管理的工作机制,通过XML、注解等方式进行事务管理配置,同时还讲解了JTA事务配置知识。   第10章:对实际应用中Spring事务管理各种疑难问题进行透彻的剖析,让读者对Spring事务管理不再有云遮雾罩的感觉。   第11章:讲解了如何使用Spring JDBC进行数据访问操作,我们还重点讲述了LOB字段处理、主键产生和获取等难点知识。   第12章:讲解了如何在Spring中集成Hibernate、myBatis等数据访问框架,同时,读者还将学习到ORM框架的混用和DAO层设计的知识。   第13章:本章重点对在Spring中如何使用Quartz进行任务调度进行了讲解,同时还涉及了使用JDK Timer和JDK 5.0执行器的知识。   第14章:介绍Spring 3.0新增的OXM模块,同时对XML技术进行了整体的了解。   第15章:对Spring MVC框架进行详细介绍,对REST风格编程方式进行重点讲解,同时还对Spring 3.0的校验和格式化框架如果和Spring MVC整合进行讲解。   第16章:有别于一般书籍的单元测试内容,本书以当前最具实战的JUnit4+Unitils+ Mockito复合测试框架对如何测试数据库、Web的应用进行了深入的讲解。   第17章:以一个实际的项目为蓝本,带领读者从项目需求分析、项目设计、代码开发、单元测试直到应用部署经历整个实际项目的整体开发过程。
2.1. 简介 2.2. 控制反转(IoC)容器 2.2.1. 新的bean作用域 2.2.2. 更简单的XML配置 2.2.3. 可扩展的XML编写 2.2.4. Annotation(注解)驱动配置 2.2.5. 在classpath中自动搜索组件 2.3. 面向切面编程(AOP) 2.3.1. 更加简单的AOP XML配置 2.3.2. 对@AspectJ 切面的支持 2.3.3. 对bean命名pointcut( bean name pointcut element)的支持 2.3.4. 对AspectJ装载时织入(AspectJ load-time weaving)的支持 2.4. 中间层 2.4.1. 在XML里更为简单的声明性事务配置 2.4.2. 对Websphere 事务管理的完整支持 2.4.3. JPA 2.4.4. 异步的JMS 2.4.5. JDBC 2.5. Web层 2.5.1. Spring MVC合理的默认值 2.5.2. Portlet 框架 2.5.3. 基于Annotation的控制器 2.5.4. Spring MVC的表单标签库 2.5.5. 对Tiles 2 支持 2.5.6. 对JSF 1.2支持 2.5.7. JAX-WS支持 2.6. 其他 2.6.1. 动态语言支持 2.6.2. 增强的测试支持 2.6.3. JMX 支持 2.6.4. 将Spring 应用程序上下文部署为JCA adapter 2.6.5. 计划任务 2.6.6. 对Java 5 (Tiger) 支持 2.7. 移植到Spring 2.5 2.7.1. 改变 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. IoC(控制反转)容器 3.1. 简介 3.2. 基本原理 - 容器和bean 3.2.1. 容器 3.2.2. 实例化容器 3.2.3. 多种bean 3.2.4. 使用容器 3.3. 依赖 3.3.1. 注入依赖 3.3.2. 依赖配置详解 3.3.3. 使用depends-on 3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton beans和prototype-bean的依赖 3.4.4. 其他作用域 3.4.5. 自定义作用域 3.5. 定制bean特性 3.5.1. 生命周期回调 3.5.2. 了解自己 3.6. bean定义的继承 3.7. 容器扩展点 3.7.1. 用BeanPostProcessor定制bean 3.7.2. 用BeanFactoryPostProcessor定制配置元数据 3.7.3. 使用FactoryBean定制实例化逻辑 3.8. The ApplicationContext 3.8.1. BeanFactory 还是 ApplicationContext? 3.8.2. 利用MessageSource实现国际化 3.8.3. 事件 3.8.4. 底层资源的访问 3.8.5. ApplicationContext在WEB应用中的实例化 3.9. 粘合代码和可怕的singleton 3.10. 以J2EE RAR文件的形式部署Spring ApplicationContext 3.11. 基于注解(Annotation-based)的配置 3.11.1. @Autowired 3.11.2. 基于注解的自动连接微调 3.11.3. CustomAutowireConfigurer 3.11.4. @Resource 3.11.5. @PostConstruct 与 @PreDestroy 3.12. 对受管组件的Classpath扫描 3.12.1. @Component和更多典型化注解 3.12.2. 自动检测组件 3.12.3. 使用过滤器自定义扫描 3.12.4. 自动检测组件的命名 3.12.5. 为自动检测的组件提供一个作用域 3.12.6. 用注解提供限定符元数据 3.13. 注册一个LoadTimeWeaver 4. 资源 4.1. 简介 4.2. Resource接口 4.3. 内置 Resource 实现 4.3.1. UrlResource 4.3.2. ClassPathResource 4.3.3. FileSyst
©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值