当前位置: 首页 > news >正文

使用Spring与JDK动态代理实现事务管理

使用Spring与JDK动态代理实现事务管理

在现代企业级应用开发中,事务管理是一项关键的技术,它可以保证一系列操作要么全部成功,要么全部失败,从而确保数据的一致性和完整性。Spring框架提供了强大的事务管理能力,但有时为了更细粒度地控制事务边界,我们可能需要自己实现事务管理逻辑。本文将介绍如何结合Spring框架和JDK动态代理技术来实现一个简单的事务管理系统。

引言

在本示例中,我们将创建一个基于Spring框架的应用程序,该程序包含一个账户服务接口(IAccountService),以及其实现类(AccountServiceImp)。为了增强该服务的事务处理能力,我们将创建一个工厂类(ProxyBeanFactory),它会为IAccountService生成一个动态代理对象,该对象能够在调用真实服务方法前后自动开启和提交事务。

XML配置

首先,我们需要配置Spring的bean定义。下面是一个简化版的Spring配置文件示例:

<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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 数据源配置略 --><!-- QueryRunner配置略 --><!-- 连接工具类配置略 --><!-- 事务工具类配置略 --><!-- 数据访问层配置略 --><!-- 业务逻辑层配置略 --><bean id="proxyService" class="org.example.service.IAccountService" factory-bean="factory" factory-method="createProxy"></bean><bean id="factory" class="org.example.factory.ProxyBeanFactory"><property name="transactionUtil" ref="transactionUtil"></property><property name="toProxyService" ref="service"/></bean><!-- 控制器配置略 --></beans>

如上所示,ProxyBeanFactory将创建一个实现了IAccountService接口的代理对象,并且会在执行业务逻辑之前和之后自动管理事务。

动态代理工厂类

接下来,我们来看一下ProxyBeanFactory类的具体实现:

package org.example.factory;import org.example.service.IAccountService;
import org.example.util.TransactionUtil;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyBeanFactory {private IAccountService toProxyService;private TransactionUtil transactionUtil;public void setToProxyService(IAccountService toProxyService) {this.toProxyService = toProxyService;}public void setTransactionUtil(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}public IAccountService createProxy() {return (IAccountService) Proxy.newProxyInstance(toProxyService.getClass().getClassLoader(),toProxyService.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try {transactionUtil.beginTx();result = method.invoke(toProxyService, args);transactionUtil.commitTx();} catch (Exception e) {transactionUtil.rollbackTx();} finally {transactionUtil.closeTx();}return result;}});}
}

ProxyBeanFactory类的核心在于createProxy方法,它使用JDK动态代理机制来创建代理对象。当任何IAccountService接口方法被调用时,都会触发InvocationHandler中的invoke方法,从而开启事务、执行业务逻辑并最终提交或回滚事务。

示例代码:

applicationContext.xml:

  <!-- 加载资源文件 --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 注入数据源 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${msg1}"/><property name="jdbcUrl" value="${msg2}"/><property name="user" value="${msg3}"/><property name="password" value="${msg4}"/></bean><bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner"><constructor-arg name="ds" ref="dataSource"/></bean><!-- 连接工具类 --><bean id="connectionUtil" class="org.example.util.ConnectionUtil"><property name="dataSource" ref="dataSource"/></bean><!-- 事务工具类 --><bean id="transactionUtil" class="org.example.util.TransactionUtil"><property name="connectionUtil" ref="connectionUtil"/></bean><bean id="mapperImp" class="org.example.dao.AccountMapperImp"><property name="queryRunner" ref="queryRunner"></property><property name="connectionUtil" ref="connectionUtil"></property></bean><bean id="service" class="org.example.service.AccountServiceImp"><property name="dao" ref="mapperImp"></property></bean><bean id="proxyService" class="org.example.service.IAccountService" factory-bean="factory" factory-method="createProxy"></bean><bean id="factory" class="org.example.factory.ProxyBeanFactory"><property name="transactionUtil" ref="transactionUtil"></property><property name="toProxyService" ref="service"/></bean><bean id="controller" class="org.example.controller.AccountControllerImp"><property name="service" ref="proxyService"></property></bean></beans>

ProxyBeanFactory:

public class ProxyBeanFactory {IAccountService toProxyService;;//装配事务工具类TransactionUtil transactionUtil;public void setAccountServiceImp(IAccountService accountServiceImp) {toProxyService = accountServiceImp;}public void setToProxyService(IAccountService toProxyService) {this.toProxyService = toProxyService;}public void setTransactionUtil(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}public IAccountService getAccountServiceImp() {return toProxyService;}//2.创建代理public IAccountService createProxy(){IAccountService proxy = (IAccountService) Proxy.newProxyInstance(toProxyService.getClass().getClassLoader(), toProxyService.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object obj = null;try {transactionUtil.beginTx();obj = method.invoke(toProxyService, args);transactionUtil.commitTx();} catch (Exception e) {e.printStackTrace();transactionUtil.rollbackTx();} finally {transactionUtil.closeTx();}return obj;}});return proxy;}
}

相关文章:

使用Spring与JDK动态代理实现事务管理

使用Spring与JDK动态代理实现事务管理 在现代企业级应用开发中&#xff0c;事务管理是一项关键的技术&#xff0c;它可以保证一系列操作要么全部成功&#xff0c;要么全部失败&#xff0c;从而确保数据的一致性和完整性。Spring框架提供了强大的事务管理能力&#xff0c;但有时…...

服务器硬件及RAID配置

服务器及 RAID 磁盘阵列介绍 RAID0 俗称 “ 条带 ” &#xff0c;它将两个或多个硬盘组成一个逻辑硬盘&#xff0c;容量是所有硬盘之和&#xff0c;因 为是多个硬盘组合成一个&#xff0c;故可并行写操作&#xff0c;写入速度提高&#xff0c;但此方式硬盘数据没有冗余&#…...

【经验总结】ShardingSphere5.2.1 + Springboot 快速开始

Sharding Sphere 官方文档地址&#xff1a; https://shardingsphere.apache.org/document/current/cn/overview/maven仓库&#xff1a;https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc 官方的文档写的很详尽到位&#xff0c;这里会截取部分…...

基于Golang实现Kubernetes边车模式

本文介绍了如何基于 Go 语言实现 Kubernetes Sidecar 模式&#xff0c;并通过实际示例演示创建 Golang 实现的微服务服务、Docker 容器化以及在 Kubernetes 上的部署和管理。原文: Sidecar Pattern with Kubernetes and Go[1] 在这篇文章中&#xff0c;我们会介绍 Sidecar 模式…...

TCP 通信全流程分析:从连接建立到数据传输的深度探索

目录 一、TCP报头 二、三次握手 三、数据传输 四、四次挥手 本文通过一次TCP通信过程的分析来学习TCP协议 一、TCP报头 如图是一份TCP报文的报头&#xff0c;标准报头是20个字节&#xff0c;还可带有选项报头&#xff0c;也就是TCP报头的最小长度是20字节。以下是对报头的各…...

4、提取H264码流中nalu

H264的NALU提取 1、nalu单元 定义nalu的存储单元&#xff0c;ebsp用来存储原始的包含起始码&#xff08;annexb格式&#xff09;的原始码流&#xff0c;sodb存储去除防竞争字节后的码流&#xff0c;prefix是3或4字节 nalu_def.h // nalu_def.h #pragma once#include <cs…...

哈佛大学单细胞课程|笔记汇总 (二)

哈佛大学单细胞课程|笔记汇总 &#xff08;一&#xff09; &#xff08;二&#xff09;Single-cell RNA-seq data - raw data to count matrix 根据所用文库制备方法的不同&#xff0c;RNA序列&#xff08;也被称为reads或tag&#xff09;将从转录本&#xff08;(10X Genomic…...

java中抽象类和接口的区别

文章目录 接口和抽象类的区别一、定义的区别1、抽象类2、接口 二、使用场景的区别1、抽象类2、接口 三、使用案例1、抽象类2、接口 接口和抽象类的区别 一、定义的区别 1、抽象类 关键字&#xff1a; abstract 是模棱两可的&#xff0c;似是而非的&#xff0c;无法给出具体明…...

Spring Boot - 在Spring Boot中实现灵活的API版本控制(下)_ 封装场景启动器Starter

文章目录 Pre设计思路ApiVersion 功能特性使用示例配置示例 ProjectStarter Code自定义注解 ApiVersion配置属性类用于管理API版本自动配置基于Spring MVC的API版本控制实现WebMvcRegistrations接口&#xff0c;用于自定义WebMvc的注册逻辑扩展RequestMappingHandlerMapping的类…...

EasyCVR视频转码:T3视频平台不支持GB28181协议,应该如何实现与视频联网平台的对接与视频共享呢?

EasyCVR视频管理系统以其强大的拓展性、灵活的部署方式、高性能的视频能力和智能化的分析能力&#xff0c;为各行各业的视频监控需求提供了优秀的解决方案。 T3视频为公网HTTP-FLV或HLS格式的视频流&#xff0c;目前T3平台暂不支持国标GB28181协议&#xff0c;因此也无法直接接…...

Spring统一处理请求响应与异常

在web开发中&#xff0c;规范所有请求响应类型&#xff0c;不管是对前端数据处理&#xff0c;还是后端统一数据解析都是非常重要的。今天我们简单的方式实现如何实现这一效果 实现方式 定义响应类型 public class ResponseResult<T> {private static final String SUC…...

SqlServer公用表表达式 (CTE) WITH common_table_expression

SQL Server 中的公用表表达式&#xff08;Common Table Expressions&#xff0c;简称 CTE&#xff09;是一种临时命名的结果集&#xff0c;它在执行查询时存在&#xff0c;并且只在该查询执行期间有效。CTE 类似于一个临时的视图或者一个内嵌的查询&#xff0c;但它提供了更好的…...

常见中间件漏洞

Tomcat CVE-2017-12615 1.打开环境&#xff0c;抓包 2.切换请求头为 PUT&#xff0c;请求体添加木马&#xff0c;并在请求头添加木马文件名 1.jsp&#xff0c;后方需要以 / 分隔 3.连接 后台弱口令部署war包 1.打开环境,进入指点位置,账户密码均为 tomcat 2.在此处上传一句话…...

elasticsearch的学习(二):Java api操作elasticsearch

简介 使用Java api操作elasticsearch 创建maven项目 pom.xml文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi…...

docker 部署 ElasticSearch;Kibana

ELasticSearch 创建网络 docker network create es-netES配合Kibana使用时需要组网&#xff0c;使两者运行在同一个网络下 命令 docker run -d \ --name es \ -e "discovery.typesingle-node" \ -v /usr/local/es/data:/usr/share/elasticsearch/data \ -v /usr/…...

k8s使用kustomize来部署应用

k8s使用kustomize来部署应用 本文主要是讲述kustomzie的基本用法。首先&#xff0c;我们说一下部署文件的目录结构。 ./ ├── base │ ├── deployment.yaml │ ├── kustomization.yaml │ └── service.yaml └── overlays└── dev├── kustomization.…...

基于开源FFmpeg和SDL2.0的音视频解码播放和存储系统的实现

目录 1、FFMPEG简介 2、SDL简介 3、视频播放器原理 4、FFMPEG多媒体编解码库 4.1、FFMPEG库 4.2、数据类型 4.3、解码 4.3.1、接口函数 4.3.2、解码流程 4.4、存储&#xff08;推送&#xff09; 4.4.1、接口函数 4.4.2、存储流程 5、SDL库介绍 5.1、数据结构 5.…...

保姆级教程,一文了解LVS

目录 一.什么是LVS tips: 二.优点&#xff08;为什么要用LVS&#xff1f;&#xff09; 三.作用 四.程序组成 五.LVS 负载均衡集群的类型 六.分布式内容 六.一.分布式存储 六.二.分布式计算 六.三.分布式常见应用 tips&#xff1a; 七.LVS 涉及相关的术语 八.LVS 负…...

【STM32】DMA数据转运(存储器到存储器)

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 DMA简介 DMA时钟使能 DMA初始化 转运起始和终止的地址 转运方向 数据宽度 传输次数 转运触发方式 转运模式 通道优先级 开启DMA通道 DMA初始化框架 更改转运次数 DMA应用实例-…...

【Android】通过代码打开输入法

获取焦点 binding.editText.requestFocus()打开键盘 val imm getSystemService(InputMethodManager::class.java) imm.showSoftInput(binding.editText, InputMethodManager.SHOW_IMPLICIT)...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...