Java-SpringAop 编程式事物实现

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();// 获取事物名称@NullableString 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();// 将会话刷新到数据存储区@Overridevoid 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、初始化jdbcTemplateDataSource 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 {@Testpublic void test1() {MyTransaction myTransaction = new MyTransaction();myTransaction.save();}
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 安装常用软件

文件传输工具 sudo yum install –y lrzsz vim编辑器 sudo yum install -y vimDNS 查询 sudo yum install bind-utils用法可以参考文章 《掌握 DNS 查询技巧,dig 命令基本用法》 net-tools包 yum install net-tools -y简单用法: # 查看端口占用情况…

实现HBase表和RDB表的转化(附Java源码资源)

实现HBase表和RDB表的转化 一、引入 转化为HBase表的三大来源:RDB Table、Client API、Files 如何构造通用性的代码模板实现向HBase表的转换,是一个值得考虑的问题。这篇文章着重讲解RDB表向HBase表的转换。 首先,我们需要分别构造rdb和hba…

ModbusTCP转Profinet网关高低字节交换切换

背景:在现场设备与设备通迅之间通常涉及到从一种字节序(大端或小端)转换到另一种字节序。大端字节序是指高位字节存储在高地址处,而小端字节序是指低位字节存储在低地址处。在不动原有程序而又不想或不能添加程序下可选用ModbusTC…

一种动态联动的实现方法

安防领域中的联动规则 有安防领域相关的开发经历的人知道,IPCamera可以配置使能“侦测”功能,并且指定仅针对图像传感器的某个区载进行侦测。除了基本的“移动侦测"外,侦测的功能点还有细化的类别,如人员侦测、车辆侦测、烟…

Springboot+Redis:实现缓存 减少对数据库的压力

🎉🎉欢迎光临,终于等到你啦🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏Redis实战与进阶 本专栏讲解Redis从原理到实践 …

nmcli --help(nmcli -h)nmcli文档、nmcli手册

文章目录 nmcli --helpOPTION解释OBJECT解释1. g[eneral]:查看NetworkManager的状态2. n[etworking]:启用或禁用网络3. r[adio]:查看无线电状态(例如,Wi-Fi)4. c[onnection]:列出所有的网络连接…

【Linux】进程优先级

🌎进程的优先级 文章目录: 进程状态 优先级相关       什么是优先级       为什么要有优先级       进程的优先级 调整进程优先级       调整优先级       优先级极限测试 Linux的调度与切换 总结 前言: 进程…

Apache Doris 2.1 核心特性 Variant 数据类型技术深度解析

在最新发布的 Apache Doris 2.1 新版本中,我们引入了全新的数据类型 Variant,对半结构化数据分析能力进行了全面增强。无需提前在表结构中定义具体的列,彻底改变了 Doris 过去基于 String、JSONB 等行存类型的存储和查询方式。为了让大家快速…

MATLAB图形绘制

一,二维图像绘制 最基础的二维图形绘制方法:plot -plot命令自动打开一个图形窗口Figure;用直线连接相邻两数据点来绘制图形 -根据图形坐标大小自动缩扩坐标轴,将数据标尺及单位标注自动加到两个坐标轴上,可自定坐标 轴&#x…

group by和min、max函数一起使用

原始数据 查询每科的最高分数 -- 查询每科最高分数 select stuId,classId,stuName,max(score) from student_score group by classId 错误的结果 这个显然不是对的,或者说不是我们想要的结果, 我们想要的结果是 原因是什么呢?我们知道使用…

AtomoVideo:AIGC赋能下的电商视频动效生成

✍🏻 本文作者:凌潼、依竹、桅桔、逾溪 1. 概述 当今电商领域,内容营销的形式正日趋多样化,视频内容以其生动鲜明的视觉体验和迅捷高效的信息传播能力,为商家创造了新的机遇。消费者对视频内容的偏好驱动了视频创意供给…

我的自建博客之旅04之Halo

我的自建博客之旅04之Halo Halo是我无意间发现的一款博客框架,如果你讨厌Hexo,Vuepress等静态框架本地编辑,构建部署等方式,如果你想要一款一次搭建,前台是博客,后台是文章维护,并且支持各种定制化折腾的博客框架,可能Halo会比较适合你。 因为我个人还是比较偏技术,…

C语言 扫雷游戏

写了这么长时间的关于C语言的基础知识,相信大家已经学会了使用C语言书写一些基础的代码,上次还编写了三子棋游戏的代码,这次我将编写一个基础版的扫雷游戏。 首先,创建三个文件,两个源文件,一个头文件&…

【C++】用红黑树模拟实现set、map

目录 前言及准备:一、红黑树接口1.1 begin1.2 end1.3 查找1.4 插入1.5 左单旋和右单旋 二、树形迭代器(正向)2.1 前置 三、模拟实现set四、模拟实现map 前言及准备: set、map的底层结构是红黑树,它们的函数通过调用红…

微信小程序小白易入门基础教程1

微信小程序 基本结构 页面配置 页面配置 app.json 中的部分配置,也支持对单个页面进行配置,可以在页面对应的 .json 文件来对本页面的表现进行配置。 页面中配置项在当前页面会覆盖 app.json 中相同的配置项(样式相关的配置项属于 app.js…

android 怎么自定义view

首先了解view的绘制流程: 所以onmeasure ---测量view onlayout---确定view大小----》所以继承ViewGroup必须要重写onlayout,确定子view 而onDraw----是继承view时候需要操作的。 所以:自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件。 自定义Vi…

一个可商用私有化部署的基于JAVA的chat-gpt网站

目录 介绍一、核心功能1、智能对话2、AI绘画3、知识库4、一键思维导图5、应用广场6、GPTS 二、后台管理功能1、网站自定义2、多账号登录支持3、商品及会员系统4、模型配置5、兑换码生成6、三方商户用户打通 结语 介绍 java语言的私有化部署的商用网站还是比较少的 这里给大家介…

第 126 场 LeetCode 双周赛题解

A 求出加密整数的和 模拟 class Solution { public:int sumOfEncryptedInt(vector<int> &nums) {int res 0;for (auto x: nums) {string s to_string(x);char ch *max_element(s.begin(), s.end());for (auto &c: s)c ch;res stoi(s);}return res;} };B 执行…

【研发日记】Matlab/Simulink技能解锁(五)——Simulink布线技巧

前言 见《【研发日记】Matlab/Simulink技能解锁(一)——在Simulink编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(二)——在Function编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(三)——在Stateflow编辑窗口Debug》 见《【研发日记】Matlab/Simulink…

C++作业day6

编程1&#xff1a; 封装一个动物的基类&#xff0c;类中有私有成员&#xff1a;姓名&#xff0c;颜色&#xff0c;指针成员年纪 再封装一个狗这样类&#xff0c;共有继承于动物类&#xff0c;自己拓展的私有成员有&#xff1a;指针成员&#xff1a;腿的个数&#xff08;整型 …