Spring 声明式事务

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 事务的特性/概念事务:一组操作要么都成功要么失败;事务的四个关键属性(ACID):原子性(atomicity):“原子”的本意是“不可再分”,事务的原子性表现为一个事务中涉及到的多个操作在逻辑上缺一不可。

事务的特性/概念

事务:一组操作要么都成功要么失败;
事务的四个关键属性(ACID):
  • 原子性(atomicity):“原子”的本意是“不可再分”,事务的原子性表现为一个事务中涉及到的多个操作在逻辑上缺一不可。事务的原子性要求事务中的所有操作要么都执行,要么都不执行。
  • 一致性(consistency):“一致”指的是数据的一致,具体是指:所有数据都处于满足业务规则的一致性状态。一致性原则要求:一个事务中不管涉及到多少个操作,都必须保证事务执行之前数据是正确的,事务执行之后数据仍然是正确的。如果一个事务在执行的过程中,其中某一个或某几个操作失败了,则必须将其他所有操作撤销,将数据恢复到事务执行之前的状态,这就是回滚。
  • 隔离性(isolation):在应用程序实际运行过程中,事务往往是并发执行的,所以很有可能有许多事务同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。隔离性原则要求多个事务在并发执行过程中不会互相干扰。
  • 持久性(durability):持久性原则要求事务执行完成后,对数据的修改永久的保存下来,不会因各种系统错误或其他意外情况而受到影响。通常情况下,事务对数据的修改应该被写入到持久化存储器中。

jar包

c3p0-0.9.1.2.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
mysql-connector-java-5.1.7-bin.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
 
基本配置:
<!--1、配置连接池  -->
    <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tx"></property>
    </bean>
<!--2、数据库的增删改查   JdbcTemplate  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>
<!--配置事务切面;控制住连接池  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>
    
<!--开启基于注解的事务功能;依赖tx名称空间  
    transaction-manager:指定事务管理器是哪个
    -->
    <tx:annotation-driven/>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
 * [1]根据isbn的值查询书的价格,
    public int getPrice(String isbn);
[2]根据isbn的值减少书的库存,假设每次都只买1本书,
    public void updateStock(String isbn);
[3]根据用户名减少用户账户中的余额,减少的额度就是书的价格
    public void updateBalance(int price,String user);
 * @author lfy
 *
 */
@Repository
public class BookDao {
    
    @Autowired
    JdbcTemplate jdbcTemplate;
    
    /**
     * [1]根据isbn的值查询书的价格,
     * public int getPrice(String isbn);
     * 操作:book
     */
    public int getPrice(String isbn){
        String sql = "select price from book where isbn=?";
        Integer price = jdbcTemplate.queryForObject(sql, Integer.class, isbn);
        return price;
    };
    
    /**
     * [2]根据isbn的值减少书的库存,假设每次都只买1本书,
     * public void updateStock(String isbn);
     * 操作:book_stock
     */
    public void updateStock(String isbn){
        String sql = "UPDATE book_stock SET stock=stock-1 WHERE isbn=?";
        jdbcTemplate.update(sql, isbn);
    }
    
    /**
     * [3]根据用户名减少用户账户中的余额,减少的额度就是书的价格
     * public void updateBalance(int price,String user);
     * 给用户减余额;account
     * String user:要减余额的用户名
     * int price:要减掉多少(减少的额度就是书的价格)
     */
    public void updateBalance(int price,String user){
        String sql = "update account set balance = balance-? where username=?";
        jdbcTemplate.update(sql, price,user);
        
    }
    
    public void updatePrice(String isbn){
        String sql = "update book set price = 999 WHERE isbn=?";
        jdbcTemplate.update(sql, isbn);
    }
}

事务注解主要添加在Service层,通过Aop来实现事务操作:

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.atguigu.dao.BookDao;

@Service
public class BookService {
    
    @Autowired
    BookDao bookDao;
    
    @Transactional(noRollbackFor=ArithmeticException.class,
            timeout=3,propagation=Propagation.REQUIRES_NEW)
    public void checkout(String username,String isbn){
        //0、查出图书价格
        int price = bookDao.getPrice(isbn);
        //1、减用户余额
        bookDao.updateBalance(price, username);
        //2、减图书的库存
        bookDao.updateStock(isbn);
        
        //Thread.sleep(3000);
        //new FileInputStream("D://ahahahah//aa.txt");
        System.out.println("结账完成....");
    }
    
    @Transactional(propagation=Propagation.REQUIRED,timeout=3)
    public void updatePrice(String isbn){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bookDao.updatePrice(isbn);
    }

}

Spring事务管理器

事务控制的属性:

propagation:事务的传播行为;我们可以通过控制指定大事务和小事务的关系;

传播(共用一个事务的情况下大事务的属性配置会传播给小事务)+行为(是否共用一个事务)。

isolation:事务的隔离级别,隔离各个事务的;
 isolation=Isolation.READ_UNCOMMITTED;
 根据实际的业务逻辑;
不适用事务的话会出现可能会出现如下问题:
  1. 脏读:同一事务期间,数据还没提交就给回滚了。
  2. 不可重复读:同一事务期间,多次读取数据内容不一样。
  3. 幻读:同一事务期间,多次读取数据,发现记录变少或者变多了。

本质上一个再读,一个在改;

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

读未提交:READ UNCOMMITTED

允许Transaction01读取Transaction02未提交的修改。

读已提交:READ COMMITTED

         要求Transaction01只能读取Transaction02已提交的修改。

可重复读:REPEATABLE READ

         确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。

串行化:SERIALIZABLE

         确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。

⑤各个隔离级别解决并发问题的能力见下表

 

⑥各种数据库产品对事务隔离级别的支持程度

 

 在Spring中指定事务隔离级别 

注解

用@Transactional注解声明式地管理事务时可以在@Transactional的isolation属性中设置隔离级别

XML

在Spring 2.x事务通知中,可以在<tx:method>元素中指定隔离级别

触发事务回滚的异常

 默认情况

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

设置途经

注解

@Transactional 注解

  1. rollbackFor属性:指定遇到时必须进行回滚的异常类型,可以为多个
  2. noRollbackFor属性:指定遇到时不回滚的异常类型,可以为多个

 

XML

在Spring 2.x事务通知中,可以在<tx:method>元素中指定回滚规则。如果有不止一种异常则用逗号分隔。

事务的超时和只读属性

简介

由于事务可以在行和表上获得锁,因此长事务会占用资源,并对整体性能产生影响。

如果一个事物只读取数据但不做修改,数据库引擎可以对这个事务进行优化。

超时事务属性:事务在强制回滚之前可以保持多久。这样可以防止长期运行的事务占用资源。

只读事务属性: 表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务。

设置

注解

@Transaction注解

XML

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

举个比较完整的xml配置:

<?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"
    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/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:component-scan base-package="com.atguigu"></context:component-scan>
    
    <!--1、配置连接池  -->
    <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/tx"></property>
    </bean>
    
    <!--2、数据库的增删改查   JdbcTemplate  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>
    
    <!--3、配置事务切面;控制住连接池  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>
    
    <!--4、开启基于注解的事务功能;依赖tx名称空间  
    transaction-manager:指定事务管理器是哪个
    -->
    <!-- <tx:annotation-driven/> -->
    
    <!--基于xml的事务配置;需要aop和tx名称空间  -->
    <!-- transactionManager事务切面 -->
    <aop:config>
        <!--指定事务管理器要切入哪些方法进行事务控制  -->
        <aop:pointcut expression="execution(* com.soyoungboy.service.*.*(..))" id="txPoint"/>
        <!-- aop:advisor:建议;  pointcut-ref:使用指定的切入点表达式切入事务 -->
        <aop:advisor advice-ref="myTxAdvice" pointcut-ref="txPoint"/>
    </aop:config>
    
    <!-- 使用tx名称空间和配置(事务建议、事务属性、事务增强);事务方法怎么执行
        id="myTxAdvice":随便起,别人要引用<aop:advisor advice-ref="myTxAdvice"
        transaction-manager="transactionManager":指定配置哪个事务管理器
     -->
    <tx:advice id="myTxAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 指定事务方法:代表所有方法是事务方法 -->
            <tx:method name="*"/>
            <tx:method name="checkout" rollback-for="java.lang.Exception"/>
            <tx:method name="updatePrice" propagation="REQUIRES_NEW"/>
            <!--以get开头的,通过只读来进行优化-->
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 基于xml配置的事务控制更多一点 -->


</beans>

 

 

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
47 9
|
2月前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
108 13
|
6月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
2月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
62 2
Spring高手之路26——全方位掌握事务监听器
|
2月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
3月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
80 1
Spring高手之路24——事务类型及传播行为实战指南
|
3月前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
102 1
|
3月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
106 3
|
5月前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
|
5月前
|
Java 测试技术 数据库
Spring事务传播机制(最全示例)
在使用Spring框架进行开发时,`service`层的方法通常带有事务。本文详细探讨了Spring事务在多个方法间的传播机制,主要包括7种传播类型:`REQUIRED`、`SUPPORTS`、`MANDATORY`、`REQUIRES_NEW`、`NOT_SUPPORTED`、`NEVER` 和 `NESTED`。通过示例代码和数据库插入测试,逐一展示了每种类型的运作方式。例如,`REQUIRED`表示如果当前存在事务则加入该事务,否则创建新事务;`SUPPORTS`表示如果当前存在事务则加入,否则以非事务方式执行;`MANDATORY`表示必须在现有事务中运行,否则抛出异常;
235 4
Spring事务传播机制(最全示例)