Java-SpringAop 编程式事物实现

news2024/9/19 12:50:06

SpringAop 编程式事物实现

1. 数据库事物特性
  • 原子性

多个数据库操作是不可分割的,只有所有的操作都执行成功,事物才能被提交;只要有一个操作执行失败,那么所有的操作都要回滚,数据库状态必须回复到操作之前的状态

  • 一致性

事物操作成功后,数据库的状态和业务规则必须一致。例如:从A账户转账100元到B账户,无论数据库操作成功失败,A和B两个账户的存款总额是不变的。

  • 隔离性

当并发操作时,不同的数据库事物之间不会相互干扰(当然这个事物隔离级别也是有关系的)

  • 持久性

事物提交成功之后,事物中的所有数据都必须持久化到数据库中。即使事物提交之后数据库立刻崩溃,也需要保证数据能能够被恢复。

2.事物隔离级别

当数据库并发操作时,可能会引起脏读、不可重复读、幻读、第一类丢失更新、第二类更新丢失等现象。

  • 脏读

事物A读取事物B尚未提交的更改数据,并做了修改;此时如果事物B回滚,那么事物A读取到的数据是无效的,此时就发生了脏读。

  • 不可重复读

一个事务执行相同的查询两次或两次以上,每次都得到不同的数据。如:A事物下查询账户余额,此时恰巧B事物给账户里转账100元,A事物再次查询账户余额,那么A事物的两次查询结果是不一致的。

  • 幻读

A事物读取B事物提交的新增数据,此时A事物将出现幻读现象。幻读与不可重复读容易混淆,如何区分呢?幻读是读取到了其他事物提交的新数据,不可重复读是读取到了已经提交事物的更改数据(修改或删除)

  • 第一类丢失更新

A事物的回滚覆盖了B事物已经提交的数据。如:账户有1000元,A事物执行取款100元操作,但未提交事物;此时B事物向账户存入100元并提交事物,账户余额改为1100元。此时A事物回滚了取款操作,账户余额被恢复成了1000元。

  • 第二类更新丢失

A事物的提交覆盖了B事物已经提交的数据。如:账户有1000元,A事物操作向账户存入100元,但未提交事物;此时B事物从账户取出100元并提交事物,账户余额改为900元;此时A事物提交事物,账户余额变为1100元。

对于以上问题,可以有多个解决方案,设置数据库事物隔离级别就是其中的一种,数据库事物隔离级别分为四个等级,通过一个表格描述其作用。

隔离级别脏读不可重复读幻象读第一类丢失更新第二类丢失更新
READ UNCOMMITTED允许允许允许允许允许
READ COMMITTED脏读允许允许允许允许
REPEATABLE READ不允许不允许允许不允许不允许
SERIALIZABLE不允许不允许不允许不允许不允许
3.Spring事物支持核心接口

在这里插入图片描述

TransactionDefinition–>定义与spring兼容的事务属性的接口

public interface TransactionDefinition {
    // 如果当前没有事物,则新建一个事物;如果已经存在一个事物,则加入到这个事物中。
    int PROPAGATION_REQUIRED = 0;
    // 支持当前事物,如果当前没有事物,则以非事物方式执行。
    int PROPAGATION_SUPPORTS = 1;
    // 使用当前事物,如果当前没有事物,则抛出异常。
    int PROPAGATION_MANDATORY = 2;
    // 新建事物,如果当前已经存在事物,则挂起当前事物。
    int PROPAGATION_REQUIRES_NEW = 3;
    // 以非事物方式执行,如果当前存在事物,则挂起当前事物。
    int PROPAGATION_NOT_SUPPORTED = 4;
    // 以非事物方式执行,如果当前存在事物,则抛出异常。
    int PROPAGATION_NEVER = 5;
    // 如果当前存在事物,则在嵌套事物内执行;如果当前没有事物,则与PROPAGATION_REQUIRED传播特性相同
    int PROPAGATION_NESTED = 6;
    // 使用后端数据库默认的隔离级别。
    int ISOLATION_DEFAULT = -1;
    // READ_UNCOMMITTED 隔离级别
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
    // READ_COMMITTED 隔离级别
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
    // REPEATABLE_READ 隔离级别
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
    // SERIALIZABLE 隔离级别
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
    // 默认超时时间
    int TIMEOUT_DEFAULT = -1;
    // 获取事物传播特性
    int getPropagationBehavior();
    // 获取事物隔离级别
    int getIsolationLevel();
    // 获取事物超时时间
    int getTimeout();
    // 判断事物是否可读
    boolean isReadOnly();
    // 获取事物名称
    @Nullable
    String getName();
}

  1. Spring事物传播特性表:
传播特性名称说明
PROPAGATION_REQUIRED如果当前没有事物,则新建一个事物;如果已经存在一个事物,则加入到这个事物中
PROPAGATION_SUPPORTS支持当前事物,如果当前没有事物,则以非事物方式执行
PROPAGATION_MANDATORY使用当前事物,如果当前没有事物,则抛出异常
PROPAGATION_REQUIRES_NEW新建事物,如果当前已经存在事物,则挂起当前事物
PROPAGATION_NOT_SUPPORTED以非事物方式执行,如果当前存在事物,则挂起当前事物
PROPAGATION_NEVER以非事物方式执行,如果当前存在事物,则抛出异常
PROPAGATION_NESTED如果当前存在事物,则在嵌套事物内执行;如果当前没有事物,则与PROPAGATION_REQUIRED传播特性相同
  1. Spring事物隔离级别表:
隔离级别脏读不可重复读幻象读第一类丢失更新第二类丢失更新
ISOLATION_DEFAULT同后端数据库同后端数据库同后端数据库同后端数据库同后端数据库
ISOLATION_READ_UNCOMMITTED允许允许允许允许允许
ISOLATION_READ_COMMITTED脏读允许允许允许允许
ISOLATION_REPEATABLE_READ不允许不允许允许不允许不允许
ISOLATION_SERIALIZABLE不允许不允许不允许不允许不允许
  • PlatformTransactionManager–>Spring事务基础结构中的中心接口
public interface PlatformTransactionManager {
    // 根据指定的传播行为,返回当前活动的事务或创建新事务。
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
    // 就给定事务的状态提交给定事务。
    void commit(TransactionStatus status) throws TransactionException;
    // 执行给定事务的回滚。
    void rollback(TransactionStatus status) throws TransactionException;
}

Spring将事物管理委托给底层的持久化框架来完成,因此,Spring为不同的持久化框架提供了不同的PlatformTransactionManager接口实现。列举几个Spring自带的事物管理器:

事物管理器说明
org.springframework.jdbc.datasource.DataSourceTransactionManager提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理
org.springframework.orm.jpa.JpaTransactionManager提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理
org.springframework.transaction.jta.JtaTransactionManager提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器事务管理器
  • TransactionStatus–>事物状态描述
  1. TransactionStatus接口
public interface TransactionStatus extends SavepointManager, Flushable {
    // 返回当前事务是否为新事务(否则将参与到现有事务中,或者可能一开始就不在实际事务中运行)
    boolean isNewTransaction();
    // 返回该事务是否在内部携带保存点,也就是说,已经创建为基于保存点的嵌套事务。
    boolean hasSavepoint();
    // 设置事务仅回滚。
    void setRollbackOnly();
    // 返回事务是否已标记为仅回滚
    boolean isRollbackOnly();
    // 将会话刷新到数据存储区
    @Override
    void flush();
    // 返回事物是否已经完成,无论提交或者回滚。
    boolean isCompleted();
}

  1. SavepointManager接口
public interface SavepointManager {
    // 创建一个新的保存点。
    Object createSavepoint() throws TransactionException;
    // 回滚到给定的保存点。
    // 注意:调用此方法回滚到给定的保存点之后,不会自动释放保存点,
    // 可以通过调用releaseSavepoint方法释放保存点。
    void rollbackToSavepoint(Object savepoint) throws TransactionException;
    // 显式释放给定的保存点。(大多数事务管理器将在事务完成时自动释放保存点)
    void releaseSavepoint(Object savepoint) throws TransactionException;
}
  1. Flushable接口
public interface Flushable {
    // 将会话刷新到数据存储区
    void flush() throws IOException;
}

4.Spring编程式事物

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `balance` int(11) DEFAULT NULL COMMENT '账户余额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='--账户表'

实现

package com.lyc.cn.v2.day08;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;

/**
 * Spring编程式事物
 * @author: LiYanChao
 * @create: 2018-11-09 11:41
 */
public class MyTransaction {

    private JdbcTemplate jdbcTemplate;
    private DataSourceTransactionManager txManager;
    private DefaultTransactionDefinition txDefinition;
    private String insert_sql = "insert into account (balance) values ('100')";

    public void save() {

        // 1、初始化jdbcTemplate
        DataSource dataSource = getDataSource();
        jdbcTemplate = new JdbcTemplate(dataSource);

        // 2、创建物管理器
        txManager = new DataSourceTransactionManager();
        txManager.setDataSource(dataSource);

        // 3、定义事物属性
        txDefinition = new DefaultTransactionDefinition();
        txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        // 3、开启事物
        TransactionStatus txStatus = txManager.getTransaction(txDefinition);

        // 4、执行业务逻辑
        try {
            jdbcTemplate.execute(insert_sql);
            //int i = 1/0;
            jdbcTemplate.execute(insert_sql);
            txManager.commit(txStatus);
        } catch (DataAccessException e) {
            txManager.rollback(txStatus);
            e.printStackTrace();
        }

    }

    public DataSource getDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/my_test?useSSL=false&useUnicode=true&characterEncoding=UTF-8");
        dataSource.setUsername("root");
        dataSource.setPassword("liyanchao1989@");
        return dataSource;
    }

}

  • 增加Gradle模块和包
// 引入spring-jdbc模块
optional(project(":spring-jdbc"))// https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp
compile group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4'// https://mvnrepository.com/artifact/mysql/mysql-connector-java
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.38'
  • 测试类及结果
package com.lyc.cn.v2.day08;

import org.junit.Test;

/**
 * @author: LiYanChao
 * @create: 2018-11-07 18:45
 */
public class MyTest {
    @Test
    public void test1() {
        MyTransaction myTransaction = new MyTransaction();
        myTransaction.save();
    }
}

运行测试类,在抛出异常之后手动回滚事物,所以数据库表中不会增加记录。

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

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

相关文章

【11】工程化

一、为什么需要模块化 当前端工程到达一定规模后,就会出现下面的问题: 全局变量污染 依赖混乱 上面的问题,共同导致了代码文件难以细分 模块化就是为了解决上面两个问题出现的 模块化出现后,我们就可以把臃肿的代码细分到各个小文件中,便于后期维护管理 前端模块化标准…

杰理-手表-卡槽式的sd卡热插拔

杰理-卡槽式的sd卡热插拔 卡槽式的sd卡热插拔,需要把TCFG_SD_ALWAY_ONLINE_ENABLE这个宏关掉

KT1328A主从一体蓝牙模块方案_主机使用流程以及开机返回信息说明

在KT6368A芯片基础上,新增KT1328A蓝牙主从一体版本,实现的是主从一体相互切换,可以设置为主机【类似于手机的角色】,也可以设置为从机角色,通过AT指令 不支持SPP,不支持低功耗 。功耗和之前KT6368A双模版本…

C#,图论与图算法,图(Graph)广度优先遍历(BFS,Breadth First Search)算法与源代码

1 深度优先算法与 宽度优先遍历 深度优先算法(DFS,Deep First Search)与 宽度优先遍历(BFS,Breadth First Search) 是树、图数据结构的基础性、标准性的遍历算法。 2 深度优先算法(DFS,Deep First Search) 深度优先搜索(DFS)是一种用于搜索图形或树数据结构的算法…

C#进阶实践项目(俄罗斯方块)

CSharp进阶实践项目--俄罗斯方块 1.需求分析 2.复用贪吃蛇开始等场景切换的代码 (自己写一遍,不难!!!) 入口: 更新接口: Game 类: BeginOrEndBaseScene 类:…

Linux/openEuler系统部署spring boot+vue前后端分离项目(nginx均衡代理)

Linux/openEuler系统部署spring bootvue前后端分离项目(nginx均衡代理) 1、系统环境准备,安装openjdk和nginx 可以看我前面的文章 华为openEuler系统安装openjdk并配置环境变量 openEuler系统安装nginx 2、打包后端SpringBoot项目并部署到…

电机学(笔记一)

磁极对数p: 直流电机的磁极对数是指电机定子的磁极对数,也等于电机电刷的对数。它与电机的转速和扭矩有直接关系。一般来说,极对数越多,电机转速越低,扭矩越大,适用于低速、高扭矩的场合;相反&…

盘古信息2023工作总结表彰大会暨2024工作说明会圆满举行

春风拂面,万物复苏,正是扬帆起航的好时节。2024年3月16日,盘古家人们齐聚一堂,一场以“新产品 新市场 新商业模式 可作为”为主题的工作总结表彰暨说明会圆满举行。本次盛会采用线上线下相结合的方式,无论是盘古东莞总…

国创证券|初学炒股,想赚钱就得了解这些!

初学者炒股: 1、开户。 购买股票需要开立一个股票账户,有了股票账户后,才干生意股票。开立账户时,选择大型的、知名度高的证券公司比较好,例如国创证券、华泰证券、国泰君安、广发证券、招商证券、海通证券、银河证券…

了解常用测试模型 -- V模型、W模型

目录 V模型 测试流程 特点 优、缺点 w模型/双v模型 测试流程 特点 优、缺点 V模型 测试流程 用户需求:产品经理将用户需求转变为软件需求 需求分析与系统设计:验证需求是否正确,确定编程语言和框架 概要设计:项目结构设…

集简云数据表支持连接MySQL数据库,实现无缝数据连接

集简云数据表作为一款轻量级数据存储表单工具,已经帮助众多用户快速创建、管理、存储数据。在传统的数据处理中,如果想将企业原有的数据库数据同步到数据表,需要手动操作进行,工作量大且耗时耗力;同时,由于…

三维铁木辛柯梁Matlab有限元编程 | 弹簧支座 | 弹性支撑单元| Matlab源码 | 理论文本 | 三维梁 | 3D梁 | 空间梁

专栏导读 作者简介:工学博士,高级工程师,专注于工业软件算法研究本文已收录于专栏:《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现,并提供所有案例完整源码;2.单元…

《手把手教你》系列技巧篇(四十二)-java+ selenium自动化测试 - 处理iframe -下篇(详解教程)

1.简介 经过宏哥长时间的查找,终于找到了一个含有iframe的网页。所以今天这一篇的主要内容就是用这个网页的iframe,宏哥给小伙伴或者童鞋们演示一下,在处理过程中遇到的问题以及宏哥是如何解决的。 2.iframe是什么 iframe就是我们常用的ifra…

CMU 10-414/714: Deep Learning Systems --hw3

实现功能 在ndarray.py文件中完成一些python array操作 我们实现的NDArray底层存储就是一个一维向量,只不过会有一些额外的属性(如shape、strides)来表明这个flat array在维度上的分布。底层运算(如加法、矩阵乘法)都…

网络安全的几个关键领域

网络安全是一个复杂且多维度的领域,涵盖了多个关键领域,涉及到信息保护、网络防护、应用安全、用户教育以及物理安全等多个方面。这些关键领域相互交织,共同构成了网络安全这一宏大且细致入微的领域。 今天德迅云安全就分享下网络安全的几个…

android studio的布局没有提示之SDK不匹配

我新建了一个项目,然后突然发现布局没有提示了: 我看了下我的build.gradle 我直接修改compileSdkVersion为30就能正常使用了

【贪心算法】Leetcode 55. 跳跃游戏 45. 跳跃游戏 I

【贪心算法】Leetcode 55. 跳跃游戏 45. 跳跃游戏 II Leetcode 55. 跳跃游戏解法1 贪心 Leetcode 45. 跳跃游戏I解法 贪心 Leetcode 55. 跳跃游戏 ---------------🎈🎈55. 跳跃游戏 题目链接🎈🎈------------------- 解法1 贪心…

【计算机网络篇】物理层(2)传输方式

文章目录 🍔传输方式⭐串行传输和并行传输⭐同步传输和异步传输🎈同步传输🎈异步传输 ⭐单向通信,双向交替通信和双向同时通信 🍔传输方式 在物理层中,传输方式是指数据在传输介质中传输的方式和方法。常见…

《论文阅读》EmpDG:多分辨率交互式移情对话生成 COLING 2020

《论文阅读》EmpDG:多分辨率交互式移情对话生成 COLING 2020 前言简介模型架构共情生成器交互鉴别器损失函数前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《EmpDG: Multi-resolution Interactive E…

牛客题霸-SQL进阶篇(刷题记录一)

本文基于前段时间学习总结的 MySQL 相关的查询语法,在牛客网找了相应的 MySQL 题目进行练习,以便加强对于 MySQL 查询语法的理解和应用。 由于涉及到的数据库表较多,因此本文不再展示,只提供 MySQL 代码与示例输出。 部分题目因…