Java事务之七——使用Transactional注解

聊聊spring事务失效的12种场景,太坑了 前言 对于从事java开发工作的同学来说,spring的事务肯定再熟悉不过了。 在某些业务场景下,如果一个请求中,需要同时写入多张表的数据。为了保证操作的原子性(要么同时成功,要么同时失败),避免数据不一致的情况,我们一般都会用到spring事务。 确实,spring事务用起来贼爽,就用一个简单的注解:@Transactional,就能轻松搞定事务。我猜大部分小伙伴也是这样用的,而且一直用一直爽。 但如果你使用不当,它也会坑你于无形。 今天我们就一起聊聊,事务失效的一些场景,说不定你已经中招了。不信,让我们 阅读详情

Java事务之七——使用Transactional注解

本文转载自:http://www.cnblogs.com/davenkin/archive/2013/02/24/java-tranaction-7.html,侵删。

  在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中,我们将讲到如何使用Java注解(Annotation)来标记需要事务处理的方法。

 

  这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码:

git clone https://github.com/davenkin/java_transaction_workshop.git

 

  首先定义Transactional注解:

复制代码
package davenkin.step6_annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional
{
}
复制代码

 

  使用注解标记事务的基本原理为:依然使用上一篇中讲到的动态代理的方式,只是在InvocationHandler的invoke方法中,首先判断被代理的方法是否标记有Transactional注解,如果没有则直接调用method.invoke(proxied, objects),否则,先准备事务,在调用method.invoke(proxied, objects),然后根据该方法是否执行成功调用commit或rollback。定义TransactionEnabledAnnotationProxyManager如下:

复制代码
package davenkin.step6_annotation;

import davenkin.step3_connection_holder.TransactionManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TransactionEnabledAnnotationProxyManager
{
    private TransactionManager transactionManager;

    public TransactionEnabledAnnotationProxyManager(TransactionManager transactionManager)
    {

        this.transactionManager = transactionManager;
    }

    public Object proxyFor(Object object)
    {
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new AnnotationTransactionInvocationHandler(object, transactionManager));
    }
}

class AnnotationTransactionInvocationHandler implements InvocationHandler
{
    private Object proxied;
    private TransactionManager transactionManager;

    AnnotationTransactionInvocationHandler(Object object, TransactionManager transactionManager)
    {
        this.proxied = object;
        this.transactionManager = transactionManager;
    }

    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable
    {
        Method originalMethod = proxied.getClass().getMethod(method.getName(), method.getParameterTypes());
        if (!originalMethod.isAnnotationPresent(Transactional.class))
        {
            return method.invoke(proxied, objects);
        }

        transactionManager.start();
        Object result = null;
        try
        {
            result = method.invoke(proxied, objects);
            transactionManager.commit();
        } catch (Exception e)
        {
            transactionManager.rollback();
        } finally
        {
            transactionManager.close();
        }
        return result;
    }
}
复制代码

 

  可以看到,在AnnotationTransactionInvocationHandler的invoke方法中,我们首先获得原service的transfer方法,然后根据originalMethod.isAnnotationPresent(Transactional.class)判断该方法是否标记有Transactional注解,如果没有,则任何额外功能都不加,直接调用原来service的transfer方法;否则,将其加入到事务处理中。

 

  在service层中,我们只需将需要加入事务处理的方法用Transactional注解标记就行了:

复制代码
package davenkin.step6_annotation;

import davenkin.BankService;
import davenkin.step3_connection_holder.ConnectionHolderBankDao;
import davenkin.step3_connection_holder.ConnectionHolderInsuranceDao;

import javax.sql.DataSource;

public class AnnotationBankService implements BankService
{
    private ConnectionHolderBankDao connectionHolderBankDao;
    private ConnectionHolderInsuranceDao connectionHolderInsuranceDao;

    public AnnotationBankService(DataSource dataSource)
    {
        connectionHolderBankDao = new ConnectionHolderBankDao(dataSource);
        connectionHolderInsuranceDao = new ConnectionHolderInsuranceDao(dataSource);
    }

    @Transactional
    public void transfer(final int fromId, final int toId, final int amount)
    {
        try
        {
            connectionHolderBankDao.withdraw(fromId, amount);
            connectionHolderInsuranceDao.deposit(toId, amount);
        } catch (Exception e)
        {
            throw new RuntimeException();
        }
    }
}
复制代码

 

  然后执行测试:

复制代码
    @Test
    public void transferFailure() throws SQLException
    {
        TransactionEnabledAnnotationProxyManager transactionEnabledAnnotationProxyManager = new TransactionEnabledAnnotationProxyManager(new TransactionManager(dataSource));
        BankService bankService = new AnnotationBankService(dataSource);
        BankService proxyBankService = (BankService) transactionEnabledAnnotationProxyManager.proxyFor(bankService);

        int toNonExistId = 3333;
        proxyBankService.transfer(1111, toNonExistId, 200);

        assertEquals(1000, getBankAmount(1111));
        assertEquals(1000, getInsuranceAmount(2222));
    }
复制代码

 

  测试运行成功,如果将AnnotationBankService中transfer方法的Transactional注解删除,那么以上测试将抛出RuntimeException异常,该异常为transfer方法中我们人为抛出的,也即由于此时没有事务来捕捉异常,程序便直接抛出该异常而终止运行。在下一篇(本系列最后一篇)文章中,我们将讲到分布式事务的一个入门例子。

【C++】构造函数之初始化列表(Initialization list of constructors) 本讲主要是构造函数的初始化列表的讲节,但是本节很重要,可以关乎后面写项目 阅读详情

相关推荐

VCS和UVM常用编译选项

VCS编译选项 -full64 在64bit模式下编译、仿真,用于64位操作系统 -j8 指定编译器可以并行编译的进程数为8 -timescale=1ns/1ps 指定仿真时间和精度 +libext+.v+.V+.sv+.svh 识别.v、.sv、.svh等多种格式文件 -sverilog 支持system verilog 编译 -f xxx.lisf 指定包含所有设计文件列表的文件名 -top test 设置顶层模块为test。(指包含.

qq_40571921的博客 9932

Spring boot 事务无效,报错:Transaction not enabled

后来想到每个service都集成了BaseService,其中的save、saveBatch等常用方法都放到了BaseService中,但是BaseService本身没有添加Transactional注解,添加后问题解决。上述方法是网上通用的方法,详细参考:https://www.cnblogs.com/kesimin/p/9546225.html,但是本地测试事务无效。报错是因为得不到事务标识,猜测可能是事务注解没生效。查找spring boot的事务使用方式,大多数都是说通过两个注解就可以了。

随便写写 1万+

利用Nginx反向代理实现GitLab自定义域名的高效配置

本文详细介绍了如何利用Nginx反向代理实现GitLab自定义域名的高效配置。通过统一域名管理、性能优化和安全加固,提升GitLab的访问效率和安全性。文章包含前期准备、GitLab基础配置、Nginx反向代理设置及常见问题排查,帮助开发者快速完成部署。

weixin_28834169的博客 163

【分布式事务】学习笔记

seata

jams3368的博客 1883

论文阅读笔记(一)细粒度图像检索

0、参考文献 [1]见微知著 http://geek.youkuaiyun.com/news/detail/191718 [2]Xiu-Shen Wei 《Selective Convolutional Descriptor Aggregation for Fine-Grained Image Retrieval》 [3]Lingxi Xie 《Fine-Grained Image Search》 1...

huang2818138的博客 1万+

对10G/40Gphy中auto-negotiation功能调试

在近期有一个项目,是一台设备中发现mac与phy之间的信号质量有一些差,报文会出现很多的crc错误码。希望可以将mac与phy之间的工作模式改为10GBASE-KR/40GBASE-KR4,从而提高信号质量,减少crc错误码。要实现10GBASE-KR/40GBASE-KR4,需要打开auto-negotiation,所以,文章主要内容是如何开启自协商,以及相关参数的解释。 需要的文档: 1、802.3协议手册 2、所调试phy的芯片手册(我自己使用的是bcm的万兆phy) 万兆phy情况摘要 PHY寄存

MTzhang_22的博客 5829

@Transactional的简单理解

默认情况下Spring中事务@Transactional的简单理解 首先声明,此文建立在默认的配置下的总结,其它需要特别配置的文中会有说明 一、两个方法互相调用时事务如何传递? Spring默认的事务传播行为都是:方法A调用方法B,如果已经开启了事务,B不会开启新的事务,用A同一个事务,如果没有事务,则会创建事务 二、在Controller层调用两个不同的Service层方法能保证事务吗?...

SenKnight 的博客 796

ValueError:Using a `device_map`, `tp_plan`, `torch.device` context manager or setting `torch.set解决方案

本文主要介绍了ValueError:Using a `device_map`, `tp_plan`, `torch.device` context manager or setting 'torch.set_default_device(device)` requires `accelerate`解决方案,希望能对使用transformers的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 3万+

springboot事务管理 注解@Transactional 无效原因,及解决办法

1.不需要在启动类加上@EnableTransactionManagement, @EnableTransactionManagement是 spring-tx 的注解,不是 spring-boot 的 spring-boot 会自动配置事务,相关的配置在 org.springframework.boot.autoconfigure.transaction.TransactionAutoConf...

liu_ares的博客 4403

(持续更新中!)详解【计算机类&面试真题】军队文职考试 ——第一期(真题+解析)| TCP、UDP的区别;程序局部性;ICMP协议及主要功能;重定位所需的计算机硬件

在当今信息化时代,军队中对于计算机专业人才的需求与日俱增。因此,了解面试和复试中常见的问题和要求对于准备应聘者来说至关重要。本文将围绕面试的准备要点、常见问题以及面试技巧进行探讨,并提供一些建议和经验。通过了解面试和复试的准备要点、常见问题以及技巧,读者将能够提升应对能力和成功率。本文为准备军队文职面试和计划考研复试的读者提供了有价值的参考和指导。通过阅读本篇博客,读者将能够获得关于军队文职计算机类面试和计算机考研复试的全面了解,提升自身的应对能力和成功率。

追光者♂:记录、分享、总结、提升,现象级专栏《Python从入门到人工智能》作者,无惧黑暗,坚信曙光 1688

lammps原子组速度的计算方法

在lammps摩擦、冲击、压痕等模拟过程中,涉及到某个原子组的整体移动,如果要输出这个原子组的整体移动速度,可以使用vcm()函数。下面是一个具体的使用案例,金刚石球在盒子内移动,输出移动过程中金刚石球在x方向的质心速度。vcm()是lammps自带的一个函数,返回原子组质心在设定方向的速度。其中,ID为group-ID,dim为方向,可设置x、y或者z方向。大家好,我是小马老师。

lammps_jiayou的博客 343

java中事物的注解_Java事务之七——使用Transactional注解

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中,我们将讲到如何使用Java注解(Annotation)来标记需要事务处理的方法。这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码:git clone https://gi...

weixin_39805255的博客 699

YOLO11涨点优化:损失函数优化 | 引入MPDIoU,利用边界框左上角和右下角距离,彻底解决重叠框匹配失效问题

【摘要】针对目标检测中重叠框匹配失效问题,本文提出基于MPDIoU损失函数的解决方案。MPDIoU通过同时约束边界框的左上角和右下角两点距离,有效解决了传统IoU损失在重叠场景下的优化歧义问题。文章首先分析YOLO系列在密集目标检测中的性能瓶颈,指出GIoU/CIoU等现有方法无法区分相同IoU值但偏移方向不同的预测框。随后详细解析MPDIoU的数学原理及其相对于主流损失函数的优势,证明两点距离约束能提供唯一优化方向。最后给出在YOLO11中实现MPDIoU的具体方案,包括核心代码修改点和架构适配建议。实验

2601_95807009的博客 171

Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation) Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(...

首先定义Transactional注解: 在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中,我们将讲到如何使用Java注解(Annotation)来标记需要事务处理的方法。 package davenkin.step6_annotation...

weixin_34255055的博客 101

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Java事务处理全解析(七)—— 像Spring一样使用Transactional注解(Annotation)

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中,我们将讲到如何使用Java注解(Annotation)来标记需要事务处理的方法。 首先定义Transactional注解: package davenkin.step6_annota

low_coder 1338

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

java事务全解析(七)--像Spring一样使用Transactional注解(Annotation)

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中,我们将讲到如何使用Java注解(Annotation)来标记需要事务处理的方法。   这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码: Git clo

java小强的博客 317

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

java事务学习笔记(七)--像Spring一样使用Transactional注解(Annotation)

在本系列的上一篇文章中,我们讲到了使用动态代理的方式完成事务处理,这种方式将service层的所有public方法都加入到事务中,这显然不是我们需要的,需要代理的只是那些需要操作数据库的方法。在本篇中,我们将讲到如何使用Java注解(Annotation)来标记需要事务处理的方法。   这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码: git clo

JordanInShenzhen的博客 743

Transactional注解详解

1、@Transactional注解可以作用于哪些地方? @Transactional 可以作用在接口、类、类方法。 作用于类:当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息。 作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。 作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代

weixin_44517305的博客 1万+

【java】@Transactional事务注解

事务(Transactional) 就是把多个要做的操作组合成一个整体,利用事务的特性来保证操作的安全性,如果一个事务做到一半出现任何错误,就会进行回滚操作,来恢复成最初的模样。@Transactional 是java中使用的注解形式的事务,也就是说可以直接使用该注解来完成事务操作.使用的位置: 该注解可以写在类或者方法上面.注意不能写在接口上。方法的权限: 必须是public的方法才可以使用该注解.

DreamSun的博客 8006

浅谈Java注解之Transactional

是Spring框架提供的一种声明式事务管理机制,它允许开发者通过注解的方式管理事务,而不需要编写繁琐的事务代码。这种机制基于AOP(面向切面编程),通过代理模式在方法执行前后添加事务管理逻辑。

a876106354的博客 806
上一篇: Java事务之六——使用动态代理(Dynamic Proxy)
下一篇: Java事务之八——分布式事务(Spring+JTA+Atomikos+Hibernate+JMS)
TaiSung
博客等级 码龄15年 49粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值