Spring-事务支持

目录

一、事务概述

二、引入事务场景

三、Spring对事务的支持 

Spring实现事务的两种方式

声明式事务之注解实现方式

    1.在Spring配置文件中配置事务管理器   

    2. 在Spring配置文件引入tx命名空间

    3. 在Spring配置文件中配置“事务注解驱动器”,通过注解的方式控制事务

    4. Service类或方法上添加@Transaction注解

    5.执行转账操作

声明式事务之全注解开发 

    1.配置类替代配置文件

    2.测试程序

    3.测试结果 

声明式事务之XML实现方式

    1.Spring配置文件

     2.编写测试程序

     3.测试结果


一、事务概述

  • 在一个业务流程中,通常需要多条DML语言共同联合完成,这多条DML语句必须同时成功或失败,这样才能保证数据的安全。
  • 事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。
  • 事务的四个处理流程
  1. 开启事务(begin transaction)
  2. 执行核心业务代码
  3. 提交事务(业务执行过程没有出现异常) (commit transaction)
  4. 回滚事务(业务执行过程中出现异常)(rollback transaction)
  • 事务的ACID特性
  1. 原子性(Atomicity)事务小的工作单元,不可划分。
  2. 一致性(Consistency)事务要么同时成功,要么同时失败。
  3. 隔离性(Isolation)隔离性实际上解决的问题是多个事务作用于同一个或者同一批数据时的并发问题,防止由于交叉执行而导致数据的不一致。一个完美的事务隔离,在每个事务看来,整个系统只有自己在工作,对于整个系统而言这些并发的事务一个接一个的执行,也仿佛只有一个事务,这样的隔离成为“可序列化(Serializability)”。当然,这样的隔离级别会带来巨大的开销,因此出现了各种各样的隔离级别,进而满足不同场景的需要。
  4. 持久性(Durability)只要事务完成,不管发生任何问题,都不应该发生数据丢失。即,事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

二、引入事务场景

以银行转账为例 ,有两个账户act1 和 act2,act1向act2转账10000,对于这个流程包括两个操作,act1减10000,act2加10000,这两步必须同时成功或者同时失败。

  • 转账成功,act 减10000, act2 加 10000 
  • 转账失败,act减10000后,因系统故障,act2没有加10000

数据库为了避免这种特殊情况的发生,提出了事务概念。例如:通过jdbc连接数据库后,可以手动开启事务,提交事务,回滚事务。我们可以借助aop技术实现事务管理,更幸运的是Spring提供了事务支持。

三、Spring对事务的支持 

  • Spring实现事务的两种方式

  1. 编程式事务 通过编写代码的方式实现事务的管理
  2. 声明式事务 基于注解方式、XML配置方式
  • 声明式事务之注解实现方式

    1.在Spring配置文件中配置事务管理器   
<!--配置事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dateSource"/>
    </bean>
    2. 在Spring配置文件引入tx命名空间
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    3. 在Spring配置文件中配置“事务注解驱动器”,通过注解的方式控制事务
<!--开启事务注解驱动器,开始事务注解。-->
    <tx:annotation-driven transaction-manager="txManager"/>
    4. Service类或方法上添加@Transaction注解
package com.xxx.bank.service.impl;

import com.xxx.bank.dao.AccountDao;
import com.xxx.bank.pojo.Account;
import com.xxx.bank.service.AccountService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service("accountService")
@Transactional
public class AccountServiceImpl implements AccountService {
    @Resource(name = "accountDao")
    private AccountDao accountDao;
    @Override
    public void transfer(String fromActno, String toActno, double money) {
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new RuntimeException("余额不足,无法转账!!!");
        }
        Account toAct = accountDao.selectByActno(toActno);
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);
        int count = accountDao.update(fromAct);
        count += accountDao.update(toAct);
        /*
        模拟异常
        String s = null;
        s.toString();
        */
        if (count != 2) {
            throw new RuntimeException("转账失败,请联系银行...");
        }
    }
}
    5.执行转账操作

当前账户情况

执行一次转账

模拟异常情况,检查是否转账成功

  • 声明式事务之全注解开发 

    1.配置类替代配置文件
package com.zhj.bank;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * @author zhj1259615665@qq.com
 * @create 2023-10-04 {16:45}
 */
@Configuration
// 开启组件扫描
@ComponentScan("com.zhj.bank")
// 开启事务管理
@EnableTransactionManagement
public class Spring6Config {
    @Bean(name = "dataSource")
    public DruidDataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3307/spring");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    @Bean(name = "txManager")
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager txManager = new DataSourceTransactionManager();
        txManager.setDataSource(dataSource);
        return txManager;
    }
}
    2.测试程序
@Test
    public void testNoXml() {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Config.class);
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        try {
            accountService.transfer("act-001", "act-002", 10000);
            System.out.println("转账成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        try {
            accountService.transfer("act-001", "act-002", 10000);
            System.out.println("转账成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    3.测试结果 

  • 声明式事务之XML实现方式

    1.Spring配置文件
<?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.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.zhj.bank"/>
    <!--配置数据源-->
    <bean id="dateSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3307/spring"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dateSource"/>
    </bean>
    <!--配置事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dateSource"/>
    </bean>
    <!--配置通知,具体的增强代码-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--配置切面-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.zhj.bank.service..*(..))"/>
        <!--切面 = 切点 + 通知-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>
     2.编写测试程序
public class BankTxTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        try {
            accountService.transfer("act-001", "act-002", 10000);
            System.out.println("转账成功...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
     3.测试结果

转账一次

模拟异常情况


        事务在数据库中是十分重要的概念,Spring提供了两种事务的支持方式,这篇博客记录了一点点的知识点,通过银行转账案例希望可以帮助你更好地理解事务。上述内容如果有错误的地方,希望大佬们可以指正。我一直在学习的路上,您的帮助使我收获更大!觉得对您有帮助的话,还请点赞支持!我也会不断更新文章!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Node.js【文件系统模块、路径模块 、连接 MySQL、nodemon、操作 MySQL】(三)-全面详解(学习总结---从入门到深化)

目录 Node.js 文件系统模块&#xff08;二&#xff09; Node.js 文件系统模块&#xff08;三&#xff09; Node.js 文件系统模块&#xff08;四&#xff09; Node.js 路径模块 Node.js 连接 MySQL Node.js nodemon Node.js 操作 MySQL Node.js 应用 Node.js 文件系统模块…

子类拷贝构造函数会调用父类拷贝构造函数吗?

一. 编译器提供的默认子类拷贝构造函数会调用父类拷贝构造函数。 #include <iostream> #include <string> using namespace std;class Parent { public:Parent(string home_address "中国") : m_home_address(home_address) {cout << "调用…

一文让你深入了解JavaSE的知识点

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

车辆动力学 | 轮胎纵滑和侧滑下的简化模型

1、轮胎模型的定义&#xff1a; ——反应轮胎力学性能&#xff08;所有侧向力、纵向力以及会正力矩等&#xff09;与侧偏角和运动状态&#xff08;滑转率和滑移率&#xff09;关系的数学模型 2、四个组成部分 胎面层、带束层、胎体、轮辋 3、简化模型的假设条件 4、起滑点&am…

深度学习毕设项目 医学大数据分析 - 心血管疾病分析

# 1 前言 &#x1f6a9; 基于大数据的心血管疾病分析 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 1 课题背景 本项目的任务是利用患者的检查结果预测心血管疾病(CVD)的存在与否。 2 数据…

网络安全应该怎么学?(0基础小白)

一、网络安全应该怎么学&#xff1f; 1.计算机基础需要过关 这一步跟网安关系暂时不大&#xff0c;是进入it行业每个人都必须掌握的基础能力。 计算机网络计算机操作系统算法与数据架构数据库 Tips:不用非要钻研至非常精通&#xff0c;可以与学习其他课程同步进行。 2.渗透技…

详解云WAF:免费GOODWAF归来

文前聊心 说说这篇文章的目的&#xff1a; 介绍一下自己的开发升级的项目&#xff1a;GOODWAF&#xff0c;看名字也能看的出来这是一款防火墙&#xff0c;但它不同于现在的软件防火墙&#xff0c;它是一款云WAF防火墙。 其实GOODWAF这个IP概念前两年就存在了&#xff0c;但为什…

基于Java SSM框架+Vue实现房屋租赁网站项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架Vue实现房屋租赁网站演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;房屋租赁系统当然也不能排除在外。房屋租赁系统是以实际运用为开发背景&…

C++模拟实现unordered_map和unordered_set

目录 1.了解哈希表 1.哈希表 1.他的实现原理就是&#xff1a; ​编辑 2.写单个数据的类型&#xff08;这边先模拟map的kv类型&#xff0c;后面会再一起改&#xff0c;这边先一步步的先简单实现他&#xff09; 3.封装整个类&#xff1a; 4.哈希表中存储string 2.哈…

Unity中Shader优化通用规则

文章目录 前言一、精度优化1、三种精度 fixed / half / float2、位置坐标、物理坐标类使用float3、HDR颜色、方向向量类使用half4、普通纹理、颜色类使用 fixed5、实际上&#xff0c;使用的精度取决于 平台 和 GPU6、现在桌面级GPU都是直接采用 float , Shader中的 fixed / hal…

【Linux】ln命令使用

ln命令 ln是linux中又一个非常重要命令&#xff0c;请大家一定要熟悉。它的功能是为某一个文件在另外一个位置建立一个同步的链接&#xff0c;这个命令最常用的参数是-s&#xff0c;具体用法是&#xff1a;ln –s 源文件 目标文件。 当我们需要在不同的目录&#xff0c;用到相…

分享5款靠谱好用,无广告不流氓的好软件

​ 话不多说&#xff0c;直入正题&#xff0c;全都是靠谱好用&#xff0c;无广告不流氓的好软件&#xff0c;可以先点赞收藏&#xff0c;以后慢慢用。 1.动态壁纸软件——Lively Wallpaper ​ Lively Wallpaper是一款可以将视频、GIF、网页、游戏等内容作为桌面壁纸的软件&am…

移动硬盘显示容量不显示文件怎么办?五种解决方法

移动硬盘是一种常用的便携式存储设备&#xff0c;可以方便地备份和传输大量的数据文件。然而&#xff0c;有时我们可能会遇到一个问题&#xff0c;即移动硬盘显示容量不显示文件怎么办&#xff1f;本文将介绍几种解决方法&#xff0c;希望能帮助大家有效解决问题。 方法一、检…

【JavaWeb】会话过滤器监听器

会话&过滤器&监听器 文章目录 会话&过滤器&监听器一、会话1.1 Cookie1.2 Session1.3 三大域对象 二、过滤器三、监听器3.1 application域监听器3.2 session域监听器3.3 request域监听器3.4 session域的两个特殊监听器3.4.1 session绑定监听器3.4.2 钝化活化监听…

IEC60730-1 Annex-H

IEC-60730安全标准法规由国际电工委员会 ( IEC ) 制定&#xff0c;该安全标准定义了家用电器嵌入式控制软件与硬件安全操作的测试与检测方法&#xff0c;以确保家电中受控设备的安全操作。IEC-60730将家用电器分为3类&#xff1a; A类 – 不用于确保设备的安全性。 例如&#…

深入了解Java8新特性-日期时间API之TemporalQuery、TemporalQueries

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概2000多字&#xff0c;预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#x…

国外客户跟我要佣金,该给不该给?

“Jack&#xff0c;这次你要是不帮我&#xff0c;我就死定了&#xff01;” 收到美国公司采购Antony的信息时&#xff0c;我有些哭笑不得&#xff0c;因为在我电脑屏幕上除了他的信息外&#xff0c;还有来自他公司监察部门的邮件&#xff1a; “jack先生&#xff0c;我们调查…

PostgreSQL-SQL联表查询LEFT JOIN 数据去重复

我们在使用left join联表查询时&#xff0c;如果table1中的一条记录对应了table2的多条记录&#xff0c;则会重复查出id相同的多条记录。 1、解决方法一 SELECT t1.* FROM table1 t1 LEFT JOIN table2 t2 ON t1.id t2.tid 第一种方法我们发现还是有重复数据 2、解决方法二…

go elasticsearch 测试实例

// 查询列表数据 func QueryOperateList(ctx context.Context, esClient *elastic.Client, index string, pageNum, pageSize int, start, end int64, execSql string, list []interface{}, operateAccount string, operateAddr string, maxRows, minRows int, dbAddr, namespa…