Spring5--事务操作

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: Spring5--事务操作

事务管理

1、什么事务


(1)事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操 作都失败


2、事务四个特性(ACID)


(1)原子性


(2)一致性


(3)隔离性


(4)持久性


典型场景:银行转账

lucy 转账 100 元 给 mary


lucy 少 100,mary 多 100


(1)建表


36e8e193956743e1aaa0a6b7937689e1.png


插入数据


32fb62fae5404e80a3836d41e00447b7.png


(2)编写bean.xml


开启 <!-- 组件扫描 -->


开启<!-- 数据库连接池 -->


注入<!-- JdbcTemplate对象 -->

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.xsd
                        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!-- 组件扫描 -->
    <context:component-scan base-package="com.jerry"></context:component-scan>
    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="jdbc:mysql://localhost:3306/user_db"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
    </bean>
    <!-- JdbcTemplate对象 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--    替代注解-->
    <!--2 配置通知-->
    <tx:advice id="txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则的方法上面添加事务-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--3 配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.jerry.service.UserService.*())"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>
    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

3)建User实体类

be24e7e965c342d096b0fb5b954b33dd.png

UserDao类-—2个抽象方法

41828136d9404792848031611e343d18.png

UserDaoImpl类

申明注解@Repository

注入JdbcTemplate

@Repository
public class UserDaoImpl implements UserDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void reduceMoney() {
        String sql = "update t_account set money=money-? where username=?";
        int i = jdbcTemplate.update(sql, 100, "lucy");
        System.out.println(i>0?"转账成功":"转账失败");
    }
    @Override
    public void addMoney() {
        String sql = "update t_account set money=money+? where username=?";
        int i = jdbcTemplate.update(sql, 100, "mary");
        System.out.println(i>0?"转账成功":"转账失败");
    }
}

UserService类–实现转账方法accountMoney()

申明注解@Service

注入UserDao

//@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    //转账的方法
    public void accountMoney() {
//        try {
        //第一步 开启事务
        //第二步 进行业务操作
        //lucy少100
        userDao.reduceMoney();
        //模拟异常
        int i = 10/0;
        //mary多100
        userDao.addMoney();
        //第三步 没有发生异常,提交事务
//        }catch(Exception e) {
        //第四步 出现异常,事务回滚
//        }
    }
}

上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现异常,有问题

解决办法:Spring事务操作

事务操作

1、事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)

2、在 Spring 进行事务管理操作

  • (1)有两种方式:编程式事务管理和声明式事务管理(使用)

3、声明式事务管理

  • (1)基于注解方式(使用)
  • (2)基于 xml 配置文件方式

4、在 Spring 进行声明式事务管理,底层使用 AOP 原理

5、Spring 事务管理 API

  • (1)提供一个接口DataSourceTransactionManager,代表事务管理器,这个接口针对不同的框架提供不同的实现类
  • 783fef40e03b4b9ea2c011ece5276186.png
  • 事务操作(注解声明式事务管理)

1、在 spring 配置文件配置事务管理器

    <!--创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

2、在 spring 配置文件,开启事务注解

(1)在 spring 配置文件引入名称空间 tx

(2)开启事务注解

<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

3、在 service 类上面(或者 service 类里面方法上面)添加事务注解

(1)@Transactional,这个注解添加到类上面,也可以添加方法上面

(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务

(3)如果把这个注解添加方法上面,为这个方法添加事务

3f6a6e5791e9452c90d36664ae0af102.png

传播行为和隔离级别

Spring定义了7种传播行为

1e56ff5946ea44d4a83cb0248ffde182.png

ioslation:事务隔离级别

(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题

(2)有三个读问题:脏读、不可重复读、虚(幻)读

(3)脏读:一个未提交事务读取到另一个未提交事务的数据

(4)不可重复读:一个未提交事务读取到另一提交事务修改数据

timeout:超时时间

  • (1)事务需要在一定时间内进行提交,如果不提交进行回滚
  • (2)默认值是 -1 ,设置时间以秒单位进行计算

readOnly:是否只读

  • (1)读:查询操作,写:添加修改删除操作
  • (2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作
  • (3)设置 readOnly 值是 true,设置成 true 之后,只能查询

rollbackFor:回滚

  • 设置出现哪些异常进行事务回滚

noRollbackFor:不回滚

  • 设置出现哪些异常不进行事务回滚

XML 声明式事务管理

第一步 配置事务管理器

第二步 配置通知

第三步 配置切入点和切面

<!--    替代注解-->
    <!--2 配置通知-->
    <tx:advice id="txadvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定哪种规则的方法上面添加事务-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--3 配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.jerry.service.UserService.*())"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>

完全注解方式实现声明式事务管理

创建配置类,使用配置类替代 xml 配置文件

@Configuration //配置类
@ComponentScan(basePackages = {"com.jerry"}) //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/user_db");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    //创建 JdbcTemplate 对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        //到 ioc 容器中根据类型找到 dataSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入 dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

Spring5 新功能

(1)整合日志框架 --log4j2

(2)@Nullable 注解 – 注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以 为空,参数值可以为空

(3)函数式注册对象

(4)整合 JUnit5 单元测试框架

(5)SpringWebflux 使用

–end–

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
4月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
10月前
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
5月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
10月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
251 0
|
10月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
1259 0
|
10月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
262 0
|
8月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
480 10
|
7月前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
528 1
|
10月前
|
SQL Java 数据库连接
Spring中的事务是如何实现的
1. Spring事务底层是基于数据库事务和AOP机制的 2. ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean 3. 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解 4. 如果加了,那么则利⽤事务管理器创建⼀个数据库连接 5. 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步 6. 然后执⾏当前⽅法,⽅法中会执⾏sql 7. 执⾏完当前⽅法后,如果没有出现异常就直接提交事务 8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务
|
10月前
|
JavaScript Java 开发者
Spring事务失效,常见的情况有哪些?
本文总结了Spring事务失效的7种常见情况,包括未启用事务管理功能、方法非public类型、数据源未配置事务管理器、自身调用问题、异常类型错误、异常被吞以及业务和事务代码不在同一线程中。同时提供了两种快速定位事务相关Bug的方法:通过查看日志(设置为debug模式)或调试代码(在TransactionInterceptor的invoke方法中设置断点)。文章帮助开发者更好地理解和解决Spring事务中的问题。
400 7