使用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动态代理实现事务管理 在现代企业级应用开发中,事务管理是一项关键的技术,它可以保证一系列操作要么全部成功,要么全部失败,从而确保数据的一致性和完整性。Spring框架提供了强大的事务管理能力,但有时…...
服务器硬件及RAID配置
服务器及 RAID 磁盘阵列介绍 RAID0 俗称 “ 条带 ” ,它将两个或多个硬盘组成一个逻辑硬盘,容量是所有硬盘之和,因 为是多个硬盘组合成一个,故可并行写操作,写入速度提高,但此方式硬盘数据没有冗余&#…...
【经验总结】ShardingSphere5.2.1 + Springboot 快速开始
Sharding Sphere 官方文档地址: https://shardingsphere.apache.org/document/current/cn/overview/maven仓库:https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc 官方的文档写的很详尽到位,这里会截取部分…...
基于Golang实现Kubernetes边车模式
本文介绍了如何基于 Go 语言实现 Kubernetes Sidecar 模式,并通过实际示例演示创建 Golang 实现的微服务服务、Docker 容器化以及在 Kubernetes 上的部署和管理。原文: Sidecar Pattern with Kubernetes and Go[1] 在这篇文章中,我们会介绍 Sidecar 模式…...
TCP 通信全流程分析:从连接建立到数据传输的深度探索
目录 一、TCP报头 二、三次握手 三、数据传输 四、四次挥手 本文通过一次TCP通信过程的分析来学习TCP协议 一、TCP报头 如图是一份TCP报文的报头,标准报头是20个字节,还可带有选项报头,也就是TCP报头的最小长度是20字节。以下是对报头的各…...
4、提取H264码流中nalu
H264的NALU提取 1、nalu单元 定义nalu的存储单元,ebsp用来存储原始的包含起始码(annexb格式)的原始码流,sodb存储去除防竞争字节后的码流,prefix是3或4字节 nalu_def.h // nalu_def.h #pragma once#include <cs…...
哈佛大学单细胞课程|笔记汇总 (二)
哈佛大学单细胞课程|笔记汇总 (一) (二)Single-cell RNA-seq data - raw data to count matrix 根据所用文库制备方法的不同,RNA序列(也被称为reads或tag)将从转录本((10X Genomic…...
java中抽象类和接口的区别
文章目录 接口和抽象类的区别一、定义的区别1、抽象类2、接口 二、使用场景的区别1、抽象类2、接口 三、使用案例1、抽象类2、接口 接口和抽象类的区别 一、定义的区别 1、抽象类 关键字: abstract 是模棱两可的,似是而非的,无法给出具体明…...
Spring Boot - 在Spring Boot中实现灵活的API版本控制(下)_ 封装场景启动器Starter
文章目录 Pre设计思路ApiVersion 功能特性使用示例配置示例 ProjectStarter Code自定义注解 ApiVersion配置属性类用于管理API版本自动配置基于Spring MVC的API版本控制实现WebMvcRegistrations接口,用于自定义WebMvc的注册逻辑扩展RequestMappingHandlerMapping的类…...
EasyCVR视频转码:T3视频平台不支持GB28181协议,应该如何实现与视频联网平台的对接与视频共享呢?
EasyCVR视频管理系统以其强大的拓展性、灵活的部署方式、高性能的视频能力和智能化的分析能力,为各行各业的视频监控需求提供了优秀的解决方案。 T3视频为公网HTTP-FLV或HLS格式的视频流,目前T3平台暂不支持国标GB28181协议,因此也无法直接接…...
Spring统一处理请求响应与异常
在web开发中,规范所有请求响应类型,不管是对前端数据处理,还是后端统一数据解析都是非常重要的。今天我们简单的方式实现如何实现这一效果 实现方式 定义响应类型 public class ResponseResult<T> {private static final String SUC…...
SqlServer公用表表达式 (CTE) WITH common_table_expression
SQL Server 中的公用表表达式(Common Table Expressions,简称 CTE)是一种临时命名的结果集,它在执行查询时存在,并且只在该查询执行期间有效。CTE 类似于一个临时的视图或者一个内嵌的查询,但它提供了更好的…...
常见中间件漏洞
Tomcat CVE-2017-12615 1.打开环境,抓包 2.切换请求头为 PUT,请求体添加木马,并在请求头添加木马文件名 1.jsp,后方需要以 / 分隔 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使用时需要组网,使两者运行在同一个网络下 命令 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的基本用法。首先,我们说一下部署文件的目录结构。 ./ ├── 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、存储(推送) 4.4.1、接口函数 4.4.2、存储流程 5、SDL库介绍 5.1、数据结构 5.…...
保姆级教程,一文了解LVS
目录 一.什么是LVS tips: 二.优点(为什么要用LVS?) 三.作用 四.程序组成 五.LVS 负载均衡集群的类型 六.分布式内容 六.一.分布式存储 六.二.分布式计算 六.三.分布式常见应用 tips: 七.LVS 涉及相关的术语 八.LVS 负…...
【STM32】DMA数据转运(存储器到存储器)
本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发 目录 DMA简介 DMA时钟使能 DMA初始化 转运起始和终止的地址 转运方向 数据宽度 传输次数 转运触发方式 转运模式 通道优先级 开启DMA通道 DMA初始化框架 更改转运次数 DMA应用实例-…...
【Android】通过代码打开输入法
获取焦点 binding.editText.requestFocus()打开键盘 val imm getSystemService(InputMethodManager::class.java) imm.showSoftInput(binding.editText, InputMethodManager.SHOW_IMPLICIT)...
Windows网页字体模糊困扰?Font Rendering油猴脚本让文字瞬间清晰锐利
Windows网页字体模糊困扰?Font Rendering油猴脚本让文字瞬间清晰锐利 【免费下载链接】GreasyFork-Scripts The open source code of this project is used for userscripts (油猴脚本) for desktop browsers, including Font Rendering (Customized) (字体渲染&…...
Mac开发者必看:如何同时管理Protobuf 2.6.1和3.19.4版本(附.proto文件编译避坑指南)
Mac开发者必看:如何同时管理Protobuf 2.6.1和3.19.4版本(附.proto文件编译避坑指南) 在跨版本协议开发中,Mac开发者常面临一个棘手问题:如何在同一台机器上同时维护Protobuf 2.6.1和3.19.4两个不兼容的版本?…...
[推荐]生产环境部署: docker+gitea+jenkins+jenkinsfile+ansible+钉钉 实现多机批量部署及其推送通知
1)打包机: giteapostgres、jenkins软件安装 (注意jenkins镜像中自动安装python和ansible环境)mkdir data, 在此目录下放好docker-compose.yml然后用docker compose up -d 在打包机部署好环境 其它工作机器什么都不用做后续都是用ansible自动完成!!![rootlocalhost soft]# cat d…...
PostgreSQL 17安装后必做的5件事:从安全加固到性能调优(附pg_hba.conf配置详解)
PostgreSQL 17安装后必做的5件事:从安全加固到性能调优 刚完成PostgreSQL 17的安装只是数据库旅程的第一步。要让这个强大的关系型数据库真正发挥生产级效能,还需要一系列精细化的配置。本文将带你完成五个关键步骤,从安全策略到性能参数&…...
主动配电网短期负荷预测与网络重构优化分析:基于IEEE33节点的实证研究
主动配电网短期负荷预测重构 以IEEE33节点为算例,有迭代图,各个节点在重构前的电压幅值及重构前后电压幅值的对比图,优化前后网络损耗数值对比,重构优化开断支路具体情况,以及在具体某节点处接入分布式电源的容量。 有…...
OpenCV多线程编程:从单线程到多线程的视频处理
一、最简单的摄像头显示程序让我们从最基础的版本开始:一个单线程程序,直接从摄像头读取并显示画面。基础版本代码#include <iostream> #include <opencv2/opencv.hpp> using namespace std;int main() {// 打开摄像头(默认摄像头…...
【Hot 100 刷题计划】 LeetCode 42. 接雨水 | C++ 动态规划与双指针题解
LeetCode 42. 接雨水 | C 动态规划与双指针双解法题解 📌 题目描述 题目级别:困难 (Hard) 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,…...
告别命令行!Auto-py-to-exe可视化打包Python程序的完整指南
1. 为什么需要可视化打包工具? 每次用PyInstaller打包Python程序时,最头疼的就是记不住那一长串命令行参数。上周我帮同事打包一个数据分析工具,光是调试--add-data参数就花了半小时,最后发现是路径写错了斜杠方向。这种经历让我意…...
工业五官:04 电感、电容、光电、超声波:谁才是工厂最强“探测四兄弟”?
04 电感、电容、光电、超声波:谁才是工厂最强“探测四兄弟”? 今天聊位置和接近传感器——就是专门干“有没有东西”“靠没靠近”“到了没”这仨活儿的。工厂里,传送带上零件一过,机械手一抓,门一开一关,全靠这四兄弟瞪大眼睛盯着。它们不吹牛,不睡觉,比你家看门狗靠谱…...
掌握AI专著写作密码,优质工具介绍助你快速完成学术专著
学术专著创作难题与AI工具助力 写学术专著的挑战,除了“能够写出来”以外,还有“能够出版并获得认可”的难题。在出版行业中,学术专著的目标群体相对狭窄,出版社对选题的学术价值和作者的影响力有严格的要求,因此很多…...
