【Spring】Spring的事务管理

news2024/11/17 23:24:22

目录

    • 1.Spring事务管理概述
      • 1.1 事务管理的核心接口
        • 1. PlatformTransactionManager
        • 2. TransactionDefinition
        • 3. TransactionStatus
      • 1.2 事务管理的方式
    • 2.声明式事务管理
      • 2.1 基于XML方式的声明式事务
      • 2.2 基于Annotation方式的声明式事务

1.Spring事务管理概述

Spring的事务管理简化了传统的事务管理流程,并且在一定程度上减少了开发者的工作量。

1.1 事务管理的核心接口

在Spring的所有JAR包中包含一个名为Spring-tx-4.3.6.RELEASE的JAR包,该包就是Spring提供的用于事务管理的依赖包。在该JAR包的org.Springframework.transaction包中有3个接口文件:PlatformTransactionManager、TransactionDefinition和TransactionStatus。

1. PlatformTransactionManager

PlatformTransactionManager接口是Spring提供的平台事务管理器,主要用于管理事务。该接口中提供了3个事务操作的方法,具体如下。

  • TransactionStatus getTransaction(TransactionDefinition definition):用于获取事务状态信息。该方法会根据TransactionDefinition参数返回一个TransactionStatus对象。TransactionStatus对象表示一个事务,被关联在当前执行的线程上。

  • void commit(TransactionStatus status):用于提交事务。

  • void rollback(TransactionStatus status):用于回滚事务。

PlatformTransactionManager接口只是代表事务管理的接口,并不知道底层是如何管理事务的,它只需要事务管理提供上面的3个方法,但具体如何管理事务则由它的实现类来完成。

PlatformTransactionManager接口有许多不同的实现类,常见的几个实现类如下。

  • org.springframework.jdbc.datasource.DataSourceTransactionManager:用于配置JDBC数据源的事务管理器。
  • org.springframework.orm.Hibernate4.HibernateTransactionManager:用于配置Hibernate的事务管理器。
  • org.springframework.transaction.jta.JtaTransactionManager:用于配置全局事务管理器。

当底层采用不同的持久层技术时,系统只需使用不同的PlatformTransactionManager实现类即可。

2. TransactionDefinition

TransactionDefinition接口是事务定义(描述)的对象,该对象中定义了事务规则,并提供了获取事务相关信息的方法,具体如下:

  • string getName():获取事务对象名称。
  • int getlsolationLeve():获取事务的隔离级别。
  • int getPropagationBehavior():获取事务的传播行为。
  • int setTimeout():获取事务的超时时间。
  • boolean isReadOnly():获取事务是否只读。

上述方法中,事务的传播行为是指在同一个方法中,不同操作前后所使用的事务。传播行为有很多种,具体如表所示。

在这里插入图片描述
在事务管理过程中,传播行为可以控制是否需要创建事务以及如何创建事务。通常情况下,数据的查询不会影响原数据的改变,所以不需要进行事务管理,而对于数据的插入、更新和删除操作,必须进行事务管理。如果没有指定事务的传播行为,Spring默认传播行为是REQUIRED。

3. TransactionStatus

TransactionStatus接口是事务的状态,描述了某一时间点上事务的状态信息。该接口中包含6个方法,具体如下:

  • void flush():刷新事务。
  • boolean hasSavepoint():获取是否存在保存点。
  • boolean isCompleted():获取事务是否完成。
  • boolean isNewTransaction():获取是否是新事务。
  • boolean isRollbackOnly():获取是否回滚。
  • void setRollbackOnly():设置事务回滚。

1.2 事务管理的方式

Spring中的事务管理分为两种方式:一种是传统的编程序事务管理;另一种是声明式事务管理。

  • 编程序事务管理:通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚。
  • 声明式事务管理:通过AOP技术实现的事务管理,其主要思想是将事务管理作为一个“切面”代码单独编写,然后通过AOP技术将事务管理的“切面”代码植入业务目标类中。

声明式事务管理最大的优点在于开发者无须通过编程的方式来管理事务,只需在配置文件中进行相关的事务规则声明,就可以将事务规则应用到业务逻辑中。这使得开发人员可以更加专注于核心业务逻辑代码的编写,在一定程度上减少了工作量,提高了开发效率。所以在实际开发中,通常都推荐使用声明式事务管理。

2.声明式事务管理

Spring的声明式事务管理可以通过两种方式来实现:一种是基于XML的方式;另一种是基于Annotation的方式。

2.1 基于XML方式的声明式事务

基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。

Spring 2.0以后,提供了tx命名空间来配置事务,tx命名空间下提供了tx:advice元素来配置事务的通知(增强处理)。当使用tx:advice元素配置了事务的增强处理后,就可以通过编写的AOP配置让Spring自动对目标生成代理。配置tx:advice元素时,通常需要指定id和transaction-manager属性,其中id属性是配置文件中的唯一标识,transaction-manager属性用于指定事务管理器。除此之外,还需要配置一个tx:attributes子元素,该子元素可通过配置多个tx:method子元素来配置执行事务的细节。

关于tx:method元素的属性描述如表所示。

在这里插入图片描述
了解了如何在XML文件中配置事务后,接下来通过一个案例来演示如何通过XML方式实现Spring的声明式事务管理。

【示例5-1】本案例以基础模拟一个会员赠送积分的功能,要求在赠送积分时通过Spring对事务进行控制,其具体实现步骤如下。

步骤01 在idea中创建一个名为chapter05的Web项目,在项目的lib目录中导入JAR包,并将AOP所需JAR包也导入lib目录中。
在这里插入图片描述
步骤02 在MySQL中,修改数据库db_spring中的数据表user,增加字段jf(积分),如图所示。同时,为了后续操作数据表方便,在数据表user中设置所有用户的初始积分为1000。

在这里插入图片描述
步骤03 将chapter00项目中的代码和配置文件复制到chapter05项目的src目录下。接下来,在User类中增加jf(积分)成员和对应的getter()和setter()方法。

  private Integer jf;//积分
    public Integer getJf() {
        return jf;
    }
    public void setJf(Integer jf) {
        this.jf = jf;
    }

在UserDao接口中创建一个赠送积分的方法transfer()。

//赠送积分
    public void transfer(String outUser, String inUser, Integer jf);

在实现类UserDaoImpl中实现transfer()方法。

   //赠送积分
    public void transfer(String outUser,String inUser, Integer jf) {
        //接受积分
        this.jdbcTemplate.update("update user set jf = jf + ? where username = ?", jf, inUser);
        //模拟系统运行时的突发性问题
        int i=1/0;
        //赠送积分
        this.jdbcTemplate.update("update user set jf = jf - ? where username = ?", jf, outUser);
    }

在上述代码中,使用了两个update()方法对user表中的数据执行接收积分和赠送积分的更新操作。在两个操作之间添加了一行代码“int i=1/0;”来模拟系统运行时的突发性问题。如果没有事务控制,那么在transfer()方法执行后,接收积分用户的积分会增加,而赠送积分用户的积分会因为系统出现问题而不变,这显然是有问题的;如果增加了事务控制,那么在transfer()方法操作执行后,接收积分用户的积分和赠送积分用户的积分在问题出现前后都应该保持不变。

步骤04 修改配置文件applicationContext.xml,添加命名空间并编写事务管理的相关配置代码。

<?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:tx="http://www.springframework.org/schema/cache"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/cache
       http://www.springframework.org/schema/cache/spring-cache.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       ">

    <!-- 1.配置数据源

    -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- 数据库驱动 -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <!-- 连接数据库url -->
        <property name="url" value="jdbc:mysql://localhost:3306/db_spring"/>
        <!-- 连接数据库的用户名 -->
        <property name="username" value="root"/>
        <!-- 连接数据库的密码 -->
        <property name="password" value="root"/>
    </bean>
    <!-- 2.配置JDBC模板 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 默认必须使用数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 定义id为 UserDao 的 Bean -->
    <bean id="UserDao" class="com.ssm.jdbc.UserDaoImpl">
        <!-- 将jdbcTemplate 注入userDao实例中 -->
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

    <!-- 4.事务管理器,依赖于数据源-->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 5.编写通知:对事务进行增强(通知),需要编写对切入点和具体执行事务细节 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"
            isolation="DEFAULT" red-only="false" />
        </tx:attributes>
    </tx:advice>
    <!-- 6.编写aop:让Spring自动对目标生产成代理,需要使用AspectJ的表达式 -->
    <aop:config>
        <!-- 切入点 -->
        <aop:pointcut id="txPointCut" expression="execution(* com.ssm.jdbc.*.*(..))"/>
        <!-- 切面 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
    </aop:config>
</beans>

定义了id为transactionManager的事务管理器,接下来通过编写的通知来声明事务,最后通过声明AOP的方式让Spring自动生成代理。

步骤05 在com.ssm.jdbc包中创建测试类TransactionTest,并在类中编写测试方法xmlTest()。

package com.ssm.jdbc;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
 * 功能描述
 *
 * @author: 衍生星球
 * @date: 2023年05月06日 17:08
 */

public class TransactionTest {
    @Test
    public void xmlTest() {
        //加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取userDao实例
        UserDao userDao = (UserDao)applicationContext.getBean("UserDao");
        //赠送积分
        userDao.transfer("zhangsan","lisi", 100);
        System.out.println("赠送积分成功!");
    }
}

获取UserDao实例后,调用了实例中的赠送积分方法,由zhangsan向lisi转入100积分。如果事务代码起作用,那么在整个赠送积分方法执行完毕后,zhangsan和lisi的积分应该都是原来的值。

2.2 基于Annotation方式的声明式事务

Spring的声明式事务管理还可以通过Annotation(注解)的方式来实现。这种方式的使用非常简单,开发者只需做两件事情:

(1)在Spring容器中注册事务注解驱动,其代码如下:

<tx:annotation-driven transaction-manager ntransactionManager" />

(2)在需要使用事务的Spring Bean类或者Bean类的方法上添加注解@Transactional。如果将注解添加在Bean类上,就表示事务的设置对整个Bean类的所有方法都起作用;如果将注解添加在Bean类中的某个方法上,就表示事务的设置只对该方法有效。

使用@Transactional注解时,可以通过其参数配置事务详情。@Transactional注解可配置的参数信息。

在这里插入图片描述
@Transactional注解与tx:method元素中的事务属性基本是对应的,并且其含义也基本相似。

【示例5-2】为了让读者更加清楚地掌握@Transactiona注解的使用,以Annotation方式实现项目中的事务管理,具体实现步骤如下。

步骤01 在src目录下创建一个Spring配置文件applicationContext-annotation.xml,在该文件中声明事务管理器等配置信息。

<?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:tx="http://www.springframework.org/schema/cache"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/cache
       http://www.springframework.org/schema/cache/spring-cache.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 1.配置数据源    -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- 数据库驱动 -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <!-- 连接数据库url -->
        <property name="url" value="jdbc:mysql://localhost:3306/db_spring"/>
        <!-- 连接数据库的用户名 -->
        <property name="username" value="root"/>
        <!-- 连接数据库的密码 -->
        <property name="password" value="root"/>
    </bean>
    <!-- 2.配置JDBC模板 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 默认必须使用数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 定义id为 UserDao 的 Bean -->
    <bean id="UserDao" class="com.ssm.jdbc.UserDaoImpl">
        <!-- 将jdbcTemplate 注入userDao实例中 -->
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

    <!-- 4.事务管理器,依赖于数据源-->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 5.编写通知:对事务进行增强(通知),需要编写对切入点和具体执行事务细节 -->
    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

注意:如果案例中使用了注解式开发,就需要在配置文件中开启注解处理器,指定扫描哪些包下的注解。这里没有开启注解处理器是因为在配置文件中已经配置了UserDaoImpl类的Bean,而@Transactional注解就配置在该Bean类中,所以可以直接生效。

步骤02 在UserDaoImpl类的transfer()方法上添加事务注解,添加后的代码如下所示。

  @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
    //赠送积分
    public void transfer(String outUser,String inUser, Integer jf) {
        //接收积分
        this.jdbcTemplate.update("update user set jf = jf + ? where username = ?", jf, inUser);
        //模拟系统运行时的突发性问题
        int i=1/0;
        //赠送积分
        this.jdbcTemplate.update("update user set jf = jf - ? where username = ?", jf, outUser);
    }

注意在实际开发中,事务的配置信息通常是在Spring的配置文件中完成的,而在业务层类上只需使用@Transactional注解即可,不需要配置@Transactional注解的属性。

步骤03 在TransactionTest类中创建测试方法annotationTest(),编辑后的代码如下所示。

 @Test
    public void annotationTest() {
        //加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-annotation.xml");
        //获取userDao实例
        UserDao userDao = (UserDao)applicationContext.getBean("userDao");
        //赠送积分
        userDao.transfer("zhangsan","lisi", 200);
        System.out.println("赠送积分成功!");
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/496584.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

惠普暗影精灵5 super 873-068rcn如何重装系统

惠普暗影精灵5 super 873-068rcn是一款家用游戏台式电脑&#xff0c;有时候你可能用久会遇到系统出现故障、中毒、卡顿等问题&#xff0c;或者你想要更换一个新的操作系统&#xff0c;这时候你就需要重装系统。重装系统可以让你的电脑恢复到出厂状态&#xff0c;清除所有的个人…

【vite+vue3.2 项目性能优化实战】打包体积分析插件rollup-plugin-visualizer视图分析

rollup-plugin-visualizer是一个用于Rollup构建工具的插件&#xff0c;它可以生成可视化的构建报告&#xff0c;帮助开发者更好地了解构建过程中的文件大小、依赖关系等信息。 使用rollup-plugin-visualizer插件&#xff0c;可以在构建完成后生成一个交互式的HTML报告&#xf…

【提示学习】Label prompt for multi-label text classification

论文信息 名称内容论文标题Label prompt for multi-label text classification论文地址https://link.springer.com/article/10.1007/s10489-022-03896-4研究领域NLP, 文本分类, 提示学习, 多标签提出模型LP-MTC(Label Prompt Multi-label Text Classification model)来源Appli…

Docker跨主机网络通信

常见的跨主机通信方案主要有以下几种&#xff1a; 形式描述Host模式容器直接使用宿主机的网络&#xff0c;这样天生就可以支持跨主机通信。这样方式虽然可以解决跨主机通信的问题&#xff0c;但应用场景很有限&#xff0c;容易出现端口冲突&#xff0c;也无法做到隔离网络环境…

buildroot系统调试苹果手机网络共享功能

苹果手机usb共享网络调试 首先了解usb基础知识&#xff0c;比如usb分为主设备和从设备进行通信&#xff0c; 1.HOST模式下是只能做主设备&#xff0c; 2.OTG模式下是可以即做主又可以做从&#xff0c;主设备即HCD&#xff0c;从设备即UDC&#xff08;USB_GADGET &#xff09…

年后准备进腾讯的可以看看....

大家好~ 最近内卷严重&#xff0c;各种跳槽裁员&#xff0c;今天特意分享一套学习笔记 / 面试手册&#xff0c;年后跳槽的朋友想去腾讯的可以好好刷一刷&#xff0c;还是挺有必要的&#xff0c;它几乎涵盖了所有的软件测试技术栈&#xff0c;非常珍贵&#xff0c;肝完进大厂&a…

多态的原理

有了虚函数&#xff0c;会在类的对象增加一个指针&#xff0c;该指针就是虚函数表指针_vfptr;虚表本质就是函数指针数组,虚表里面存放着该对象的虚函数的地址&#xff1b; 派生类继承有虚函数基类的对象模型 子类继承父类的虚表指针时&#xff0c;是对父类的虚表指针进行了拷…

密码学:古典密码.

密码学&#xff1a;古典密码. 古典密码是密码学的一个类型&#xff0c;大部分加密方式是利用替换式密码或移项式密码&#xff0c;有时是两者的混合。古典密码在历史上普遍被使用&#xff0c;但到现代已经渐渐不常用了。一般来说&#xff0c;一种古典密码体制包含一个字母表(如…

MATLAB 点云均匀体素下采样(6)

MATLAB 点云均匀体素下采样的不同参数效果测试 (6) 一、实现效果二、算法介绍三、函数说明3.1 函数3.2 参数四、实现代码(详细注释!)一、实现效果 不同参数调整下的均匀体素下采样结果如下图所示,后续代码复制黏贴即可: 分别为0.3m,0.2m,0.1m尺度下的格网下采样结果…

【C++复习2】C++编译器的工作原理

如果你是一名newbird的话&#xff0c;建议观看如下视频加深你的理解&#xff0c;再看如下内容&#xff1a; https://www.bilibili.com/video/BV1N24y1B7nQ?p7 The cherno会额外告诉你如何将目标文件转换成汇编代码&#xff0c;CPU执行指令的过程以及编译器如何通过删除冗余变…

【MySQL】SQL优化

上一篇索引是针对查询语句进行优化,但在MySQL中可不仅有查询语句,针对其他的SQL语句同样也能进行优化 文章目录 1.插入数据2.主键优化3.order by 优化4.group by优化5.limit优化6.update优化 1.插入数据 插入数据所使用的关键字为insert,SQL语句为 insert into 表名(字段1,字…

Huntly: 一款超强大的自托管信息管理工具,支持管理RSS、自动保存网页、稍后阅读

Huntly是一款开源的自托管信息管理工具&#xff0c;旨在帮助用户更好地管理和处理各种信息。Huntly可以通过管理RSS、自动保存网页和稍后阅读等功能来帮助用户更有效地收集、保存和浏览信息。 github 地址&#xff1a;GitHub - lcomplete/huntly: Huntly, information manageme…

服务器的基本概念与初始Ajax

1. 客户端与服务器 1.1 上网的目的 刷微博、看新闻、听歌、看电影。。。 本质目的&#xff1a;通过互联网的形式来获取和消费资源 1.2 服务器 上网过程中&#xff0c;负责存放和对外提供资源的电脑&#xff0c;叫做服务器。 1.3 客户端 上网过程中&#xff0c;负责获取…

如何用ChatGPT搭建品牌文本体系?(品牌名+slogan+品牌故事)

该场景对应的关键词库&#xff08;26个&#xff09;&#xff1a; 品牌名、奶茶、中文名、情感联想度、饮料、价值观/理念、发音、slogan、产品功能导向、行业性质导向、经营理念导向、消费者观念导向、口语化、修辞手法、品牌故事、创始人初心品牌故事、里程碑事件故事、产品初…

OpenPCDet系列 | 3.框架训练准备流程

文章目录 训练准备流程1. dataloader部分2. network部分3. optimizer部分4. scheduler部分训练准备流程 对于OpenPCDet中模型的训练过程如下所示,在训练前一般需要进行4个部分的准备:数据准备、网络模型准备、以及优化器和学习率调度器。下面对这4个大部分分别介绍。主要就是…

【PWN刷题__ret2syscall】[Wiki] ret2syscall

初次接触到ret2syscall&#xff0c;而ret2syscall的题目目前没有在各大平台的题目类型筛选中找到&#xff0c;所以还是刷一刷Wiki的经典题目吧&#xff01;过程中遇到很多问题&#xff0c;包括偏移量的计算、ret2syscall原理的理解等等。尝试以萌新的视角&#xff0c;来分享、解…

我们给AutoGPT写了个插件,手把手看看它的玩法~

目录 先保证你电脑里安装了 Python&#xff0c;然后使用的第一步是安装运行需要的库&#xff0c;这需要你输入这行代码 它会安装这个 txt 文件里面所有的库&#xff0c;比如openai库是用来调用 ChapGPT 的功能&#xff0c;beautifulsoup4库是用来解析网页内容等等。 到此为止…

间谍软件开发商利用漏洞利用链攻击移动生态系统

导语&#xff1a;间谍软件开发商结合使用了零日漏洞和已知漏洞。谷歌TAG的研究人员督促厂商和用户应加快给移动设备打补丁的步伐。 间谍软件开发商利用漏洞利用链攻击移动生态系统去年&#xff0c;几家商业间谍软件开发商开发并利用了针对 iOS 和安卓用户的零日漏洞。然而&…

Vue3项目中使用ECharts图表并实现自适应效果

文章目录 一、Vue3项目安装ECharts二、引入、使用ECharts1.创建图表组件&#xff0c;并在父组件中引入使用2.引入ECharts3.ECharts图表自适应 总结 一、Vue3项目安装ECharts 在项目中输入如下代码&#xff1a; npm install echarts --save安装完成可以在package.json中看到&a…

Vuex在项目中的实际应用

前言 最近让我搞一个关怀版本的系统。纯纯前端、无语死。就是整个系统的字体还有框框啥的变大。简单暴力的做法就是重新写一套样式咯,这不纯纯累死人啊。琢磨了一下,如果可以保存关怀版的一个标志,然后全部组件都可以获取到该标志。通过该标志,然后动态的指定类的样式。 V…