Spring事务

@Transactional事务回滚异常:Transaction rolled back because it has been marked as rollback-only 本文主要探讨了一个常见的Spring框架中的事务管理问题,即事务回滚异常@Transactional。首先,通过问题描述,让读者了解这个问题的现象和影响。然后,通过原因分析,深入解析了导致这个问题的几种可能原因,包括异常示例代码和查看源码。最后,通过解决方案部分,给出了解决这个问题的几种方法,并推荐了最佳实践。通过本文,读者可以更好地理解Spring框架中的事务管理机制,并学会如何解决常见的事务回滚异常问题。 阅读详情

1.事务的回顾

1)什么事务

事务:逻辑上的一-组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。

2)事务的特性

原子性:事务不可分割
一致性: 事务执行前后数据完整性保持-致
隔离性:一个事务的执行不应该受到其他事务的干扰
持久性: - -旦事务结束,数据就持久化到数据库

3)如果不考虑隔离性引发安全性问题

读问题.

  • 脏读:一个事务读到另一个事务未提交的数据
  • 不可重复读:一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
  • 虚读、幻读:一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致
    写问题
    丢失更新(锁机制:悲观锁、乐观锁)

4)解决读问题

设置事务的隔离级别
Read uncommitted ::未提交读,任何读问题解决不了。
Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。
Repeatable read:重复读,解决脏读和不可重复读,但是虚读有可能发生。(MySQL默认)

Serializable :解决所有读问题。

2.Spring的事务管理的API

PlatformTransactionManager:平台事务管理器
平台事务管理器:接口,是Spring用 于管理事务的真正的对象。

DataSourceTransacti onManager :底层使用JDBC管理事务
HibernateTransact ionManager :底层使用Hibernate管理事务

TransactionDefinition :事务定义信息
事务定义:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读
I
TransactionStatus:事务的状态
I事务状态: 用于记录在事务管理过程中, 事务的状态的对象。

3.事务管理的API的关系

Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。

4.Spring的事务的传播行为

Spring的传播行为
Spring中提供了七种事务的传播行为:

保证多个操作在同一个事务中
PROPAGATION REOUIRED :默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
PROPAGATION SUPPORTS :支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
PROPAGATION MANDATORY :如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。

保证多个操作不在同一个事务中,
PROPAGATION REOUIRES NEW :如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建-一个新事务,包含自身操作。
PROPAGATION NOT SUPPORTED :如果A中有事务,将A的事务挂起。不使用事务管理。
PROPAGATION NEVER :如果A中有事务,报异常。

嵌套式事务
PROPAGATION NESTED :嵌套事务,如果A中有事务,按照A的事务执行,执行完成
后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以
选择回滚到最初始位置,也可以回滚到保存点。

5.Spring的事务管理(银行转账演示)

场景:
A给B转账,需要A的账户,B的账户已经转账金额,当A账户扣钱成功且B账户加钱成功,说明转账成功,其余情况转账失败。只有成功的情况下才会将数据写入数据库。

public class UserServiceImpl implements UserService{
    UserDao userDao = new UserDao();
    @Override
    public String aToB(String aname,String bname,int money) {
        //参数校验
        if(StringUtils.isEmpty(aname)||StringUtils.isEmpty((bname))){
            return "转账用户不能为空";
        }
        if(money<=0){
            return "转账金额不能小于0";
        }
        //转账
        //1.a扣钱
        int a = userDao.updateByUnameAndMoneySub(aname,money);
        //2.b加钱
        int b = userDao.updateByUnameAndMoneyAdd(bname,money);

        return a>0&&b>0?"转账成功":"转账失败";
    }
}
public class UserDao {

    public int updateByUnameAndMoneySub(String uname,int money){
        //创建spring核心容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdt = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //扣钱
        String sql = "UPDATE users SET money=money-? WHERE name=? ";
        int a = jdt.update(sql, money,uname);

        return a;
    }

    public int updateByUnameAndMoneyAdd(String uname,int money){
        //创建spring核心容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdt = (JdbcTemplate) ac.getBean("jdbcTemplate");
        //加钱
        String sql = "UPDATE users SET money=money+? WHERE name=? ";
        int a = jdt.update(sql, money,uname);

        return a;
    }

}

6. Spring的事务管理:

一类:编程式事务(需要手动编写代码) -了解
引入新的约束:

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

package com.xhl.dao;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

public class UserDao {
    JdbcTemplate jdt;

    public JdbcTemplate getJdt() {
        return jdt;
    }

    public void setJdt(JdbcTemplate jdt) {
        this.jdt = jdt;
    }

    public int updateByUnameAndMoneySub(String uname, int money){

        //扣钱
        String sql = "UPDATE users SET money=money-? WHERE name=? ";
        int a = jdt.update(sql, money,uname);

        return a;
    }

    public int updateByUnameAndMoneyAdd(String uname,int money){

        //加钱
        String sql = "UPDATE users SET money=money+? WHERE name=? ";
        int a = jdt.update(sql, money,uname);

        return a;
    }

}

<?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-4.2.xsd
       http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context-4.2.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:property-placeholder location="classpath:db.properties"/>


    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>


    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

<!--    管理业务层-->
    <bean id="userService" class="com.xhl.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <property name="template" ref="transactionTemplate"/>

    </bean>
    
<!--    管理数据层-->
    <bean id="userDao" class="com.xhl.dao.UserDao">
        <property name="jdt" ref="jdbcTemplate"/>
    </bean>

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

<!--    配置事务管理的模板-->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>



</beans>
package com.xhl.service;

import com.xhl.dao.UserDao;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;

public class UserServiceImpl implements UserService{
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
//  注入平台事务管理模板
    private TransactionTemplate template;

    public TransactionTemplate getTemplate() {
        return template;
    }

    public void setTemplate(TransactionTemplate template) {
        this.template = template;
    }

    static String msg = "";
    @Override
    public String aToB(String aname,String bname,int money) {

        template.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                //参数校验
                if(StringUtils.isEmpty(aname)||StringUtils.isEmpty((bname))){
                    msg= "转账用户不能为空";
                }
                if(money<=0){
                    msg="转账金额不能小于0";
                }
                //转账
                //1.a扣钱
                int a = userDao.updateByUnameAndMoneySub(aname,money);

//                人为异常(执行到这一步出现异常后会回滚之前的操作
                int x = 1/0;

                //2.b加钱
                int b = userDao.updateByUnameAndMoneyAdd(bname,money);

                msg= a>0&&b>0?"转账成功":"转账失败";
            }
        });
        return msg;
    }
}

@Test
    public void test1(){
        //创建spring核心容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        String aname = "a用户",bname = "b用户";
        int money = 10;
        UserService userService = ac.getBean("userService",UserServiceImpl.class);
        String s = userService.aToB(aname,bname,money);
        System.out.println(s);
    }

7. Spring的事务管理:

二类:声明式事务管理(通过配置实现) _ AOP
XML方式的声明式事务管理

第一步:引入aop的开发包(用maven的工程,直接导入坐标)
第二步:恢复转账环境
第三步:配置事务管理器‘

<!--    使用AOP的事务-->
    <tx:advice id="interceptor" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="aToBByAOP" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--    配置AOP,这里相当于把事务增强的通知放入到切入点中,即给需要增强的类下的方法通知-->
    <aop:config>
        <aop:pointcut id="p1" expression="execution(* com.xhl.service.UserService.aToBByAOP(..))"/>
        <aop:advisor advice-ref="interceptor" pointcut-ref="p1"/>
    </aop:config>
//      声明式事务处理
    @Override
    public String aToBByAOP(String aname, String bname, int money) {
        //参数校验
        if(StringUtils.isEmpty(aname)||StringUtils.isEmpty((bname))){
            return "转账用户不能为空";
        }
        if(money<=0){
            return "转账金额不能小于0";
        }
        //转账
        //1.a扣钱
        int a = userDao.updateByUnameAndMoneySub(aname,money);

//                人为异常
        int x = 1/0;

        //2.b加钱
        int b = userDao.updateByUnameAndMoneyAdd(bname,money);

        return a>0&&b>0?"转账成功":"转账失败";
    }

注解方式的声明式事务管理
第一步:引入aop的开发包
第二步:恢复转账环境
第三步:配置事务管理器

在这里插入图片描述

Transaction rolled back because it has been marked as rollback-only 阅读详情

相关推荐

Spring 本地事务

Spring 本地事务、Spring 事务的传播行为、本地事务失效分析

DolphinHome的博客 1157

spring 事务问题:Transaction rolled back because it has been marked as rollback-only

问题描述: 同事测试时使用异常数据,代码报错但是并不是异常产生的错误,而出现: Transaction rolled back because it has been marked as rollback-only 中文翻译就是: 事务已回滚,因为它被标记成了只回滚 代码片段: // 我的代码 @Transactional(readOnly = true, rollbackFor = Exception.class) public String select(Stri

sunayn的博客 2万+

出现 Transaction rolled back because it has been marked as rollback-only 解决方法

出现 Transaction rolled back because it has been marked as rollback-only 解决方法

码农研究僧的博客 1万+

【Spring】Spring事务和事务传播机制

Spring事务和事务传播机制

2403_87459748的博客 2825

Spring事务和MySQL事务详解面试

文章目录数据库事务事务是什么事务的四大特性MySQL事务隔离级别查看MySQL当前事务隔离级别MySQL默认操作模式为自动提交模式JDBC处理事务Spring事务Spring的事务传播PROPAGATION_REQUIREDPROPAGATION_SUPPORTSPROPAGATION_MANDATORYPROPAGATION_REQUIRES_NEWPROPAGATION_NOT_SUPPORTEDPROPAGATION_NEVERPROPAGATION_NESTEDSpring事务的隔离级别Spring

用文字记录下每一个瞬间的感动和每一次思考的火花 23万+

C#集成Bartender:动态图片标签打印的实战与优化

本文详细介绍了在C#程序中集成Bartender实现动态图片标签打印的实战方法与优化策略。通过具名数据源绑定、图片对象尺寸控制等核心技巧,解决了动态图片显示/隐藏的难题,并提供了从模板设计、代码架构到性能优化、错误处理的全流程指南,帮助开发者构建稳定高效的工业级标签打印系统。

weixin_29216957的博客 431

Spring之事务详解

1.Spring事物的定义: 事务,就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。 如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。 当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。 由于其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。 2. spring七个事务传播属性: PROP......

上善若泪 1万+

保姆级教程:用Vue3+Element Plus快速搭建Flowable流程定义管理后台界面

本文提供了一份详细的Vue3+Element Plus教程,指导开发者快速搭建Flowable流程定义管理后台界面。从项目初始化、核心页面设计到响应式数据处理,全面覆盖前端开发关键步骤,帮助提升企业级应用开发效率。

weixin_42662293的博客 478

Spring事务专题(四)Spring中事务的使用、抽象机制及模拟Spring事务实现

点击蓝色“程序员DMZ ”关注我哟 好看记得加个“星标”哈! 前言 本专题大纲如下: 事务专题大纲 「对于专题大纲我又做了调整哈,主要是希望专题的内容能够更丰富,更加详细」,本来是想在源码分析的文章中附带讲一讲事务使用中的问题,这两天想了想还是单独写一篇并作为事务专题的收尾篇,也是我Spring源码专题的收尾篇。 本文大纲如下: Spring事务应用大纲 在看这篇文章,以及下篇源码分析的文章我希望你对Spring AOP以及有充分的了解,不然一些细节问题你可能看不明白,关于Spring AOP如果

做一个认真的程序员 3067

全网最详细Seurat v5 流程复现(拿来即用)

本文是基于seurat v5版本的教程复现,主要依据来源于官网seurat v5建议大家有时间的话可以去官网进行详细阅读学习!本节内容在之前seurat v4的教程都很多都有提到,文章所用到的数据及代码已经给各位放在这里了,有需要自取!请点击这里哦提取码:bui1。

ZxVSaccount的博客 1万+

MWORKS 2025a电气模型库实战:手把手教你搭建全桥LLC电路(附避坑指南)

本文详细介绍了如何使用MWORKS 2025a电气模型库搭建全桥LLC电路,包括环境准备、电路拓扑构建、参数优化及故障诊断。通过实战案例和避坑指南,帮助电源工程师高效设计谐振转换器,提升转换效率至98%以上。文章特别强调了Modelica模型库在电气系统建模中的关键作用。

s8t9u0v1w的博客 603

Spring 事务详解

上一章我们介绍了Spring AOP,今天来讲解Spring事务什么是事务?为什么需要事务?Spring 中事务的实现1.编程式事务2.声明式事务@Transactional详解1. REQUIRED(默认值)3.NEVER4.Nested如果各位对文章的内容感兴趣的话,请点点小赞,关注一手不迷路,讲解的内容我会搭配我的理解用我自己的话去解释如果有什么问题的话,欢迎各位评论纠正 🤞🤞🤞N_0050-优快云博客java SE_N_0050的博客-优快云博客。

N_0050的博客 2824

松灵机器人——ROS下的CAN通讯调试(内含所需调用包,都是操作步骤)

松灵机器人——ROS下的CAN通讯调试(都是操作步骤) 1 代码包地址 scout_ros package:https://github.com/westonrobot/scout_ros.git ugv_sdk-main package:https://github.com/westonrobot/ugv_sdk webots package:https://cyberbotics.com/ 2 硬件准备 2.1 SCOUT MINI 小白车 + 尾部航空插头 + CAN_TO_USB适配器

weixin_48924581的博客 1万+

Spring事务和事务传播机制

本章介绍了Spring 事务与事务传播机制,与MySQL中的事务有相同之处,也有不同之处

matexiang的博客 1953

NVIDIA Jetson之交叉编译工具

参考:http://bbs.xfyun.cn/forum.php?mod=viewthread&amp;tid=33630 用TX2做红外热成像仪的识别,厂家不提供源码,只能提供对应版本的SDK,但是需要我们自己提供交叉编译器 由于之前没有做过交叉编译相关工作,对编译工具不太了解,因此查找相关资料学习下 交叉编译知识 一般来说,针对嵌入式平台的开发有两种编译模式:原生编译和交叉编译。原生编...

ZONGXP的博客 8383

STM32面试知识点总结分析

通过Boot引脚设定,寻找初始地址初始化栈指针 __initial_sp指向复位程序 Reset_Hander设置异常中断 HardFault_Handler设置系统时钟 SystemInit调用C库函数 _main。

嵌入式技术开发 2513

【Spring框架】Spring事务的原理

本文将详细讲解Spring事务管理地底层原理,让你彻底搞懂Spring事务的运行机制。

小七的博客 3294

uniapp:实现APP获取陀螺仪数据、加速传感器、线性加速传感器,uniApp实时监听陀螺仪【XYZ】数据及停止监听与资源释放等功能示例源码,根据需求做功能(完美兼容Android安卓、苹果ios)

uniapp陀螺仪,uniapp加速传感器,uniapp线性加速传感器,APP陀螺仪数据,uniapp app 端获取陀螺仪数据示例代码,手机中获取陀螺仪的数据,uniApp实时获取陀螺仪xyz数据,android陀螺仪方向,获得陀螺仪传感器,处理传感器数据,停止监听与资源释放,Android使用陀螺仪,uniapp苹果ios陀螺仪,uni-app设备之(加速计,罗盘,陀螺仪)插件安卓/IOS APP提供了获取陀螺仪数据的能力,手机陀螺仪传感器获得手机自身旋转的角度,陀螺仪获取旋转角度,陀螺仪、加速度传感器

✅ 精选推荐文章 4266

【Spring】事务总结

事务是逻辑上的一组操作,要么都执行,要么都不执行。Guide 哥:大家应该都能背上面这句话了,下面我结合我们日常的真实开发来谈一谈。我们系统的每个业务方法可能包括了多个原子性的数据库操作,比如下面的方法中就有两个原子性的数据库操作。这些原子性的数据库操作是有依赖的,它们要么都执行,要不就都不执行。事务能否生效数据库引擎是否支持事务是关键。比如常用的 MySQL 数据库默认使用支持事务的innodb引擎。但是,如果把数据库引擎变为myisam,那么程序也就不再支持事务了!

2301_79456272的博客 1265

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

【Spring事务】

Spring事务是对数据库事务的封装,确保逻辑工作单元的一系列操作要么全部成功,要么全部失败。事务具有四大特性:原子性、一致性、隔离性和持久性。Spring事务通过PlatformTransactionManager实现事务的提交和回滚,支持多种隔离级别(如读未提交、读已提交、可重复读、串行化)和传播行为(如REQUIRED、SUPPORTS、REQUIRES_NEW等)。此外,Spring事务允许自定义回滚规则、设置只读事务、以及通过编程式和声明式两种方式管理事务。声明式事务通过AOP实现,配置灵活且不侵

qq_46005538的博客 1235

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: 1128. 等价多米诺骨牌对的数量
下一篇: 724. 寻找数组的中心索引
哆唻咪à
博客等级 码龄9年 0粉丝 105原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值