简介

Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。

Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

Spring事物管理涉及接口联系如下:

Spring事物接口详解

  • TransactionDefinition

    default int getPropagationBehavior(): 获取事物传播行为;

    default int getIsolationLevel(): 获取事物隔离级别;

    default int getTimeout(): 获取事物超时时间;

    default boolean isReadOnly(): 获取事物是否只读;

    default String getName(): 获取事物对象名字。

读写型事物: 增加、删除、修改开启事物

只读型事物: 执行查询时,也会开启事物

  • PlatformTransactionManager

    TransactionStatus getTransaction(@Nullable TransactionDefinition definition):获取事物状态行为;

    void commit(TransactionStatus status) throws TransactionException: 提交事物;

    void rollback(TransactionStatus status) throws TransactionException: 回滚事物。
  • TransactionStatus

    boolean hasSavepoint():获取是否存在存储点;

    void flush():刷新事物;

    boolean isNewTransaction():获取事物是否为新的事物;

    void setRollbackOnly():获取事物是否回滚;

    boolean isRollbackOnly():设置事物回滚;

    boolean isCompleted():获取事物是否完成。

事物的传播行为

传播行为 含义
PROPAGATION_REQUIRED 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
PROPAGATION_SUPPORTS 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
PROPAGATION_REQUIRES_NEW 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_NOT_SUPPORTED 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_NEVER 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

Spring事物实现两种方式

声明事事物

  • 简介

Spring给了一个约定(AOP开发也给了我们一个约定),如果使用的是声明式事务,那么当你的业务方法不发生异常(或者发生异常,但该异常也被配置信息允许提交事务)时,Spring就会让事务管理器提交事务,而发生异常(并且该异常不被你的配置信息所允许提交事务)时,则让事务管理器回滚事务。

  • 注解(Transactional)属性

readOnly:

该属性在不同的数据库中代表含义不相同,在mysql中代表本事物中只能执行查询语句,同时进行一些特定的优化,如果执行更新,则报错,在Oracle和sqlserver中暗示这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。但如果执行更新,不会报错。

rollbackFor:

By default, a transaction will be rolling back on {@link RuntimeException}
and {@link Error} but not on checked exceptions (business exceptions). See
{@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}

注释说明 默认遇到RuntimeException及其子类回滚,CheckedException则不被回滚,而IOException、SQLException等以及用户自定义的Exception异常都属于CheckedException,故一般写上rollbackFor=Exception.class,这样Exception以及其子类都将回滚。

propagation:

同一个类中方法互相调用会导致传播行为和事物失效问题参考:

https://www.cnblogs.com/xiaofengshan/p/15516714.html

NESTED和REQUIRED_NEW区别请参考:

https://www.cnblogs.com/xiaofengshan/p/15516720.html

分布式实现事物

本地消息表(MQ 异步确保)

这种实现方式的思路,其实是源于ebay,后来通过支付宝等公司的布道,在业内广泛使用。其基本的设计思想是将远程分布式事务拆分成一系列的本地事务。如果不考虑性能及设计优雅,借助关系型数据库中的表即可实现。



基本思路就是:

消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过 MQ 发送到消息的消费方。如果消息发送失败,会进行重试发送。

消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。

生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。如果有靠谱的自动对账补账逻辑(防止消息会被重复投递,增加消息应用状态表(message_apply),通俗来说就是个账本,用于记录消息的消费情况,每次来一个消息, 在真正执行之前,先去消息应用状态表中查询一遍,如果找到说明是重复消息,丢弃即可,如果没找到才执行,同时插入到消息应用状态表(同一事务)),这种方案还是非常实用的。

这种方案遵循 BASE 理论,采用的是最终一致性,比较适合实际业务场景的,即不会出现像 2PC 那样复杂的实现(当调用链很长的时候,2PC 的可用性是非常低的),也不会像 TCC 那样可能出现确认或者回滚不了的情况。

优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。

缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理,而且,关系型数据库的吞吐量和性能方面存在瓶颈,频繁的读写消息会给数据库造成压力。

如果消费方处理失败。且生产方无法回滚,如支付宝支付,则采用邮件通知人工进行手工补偿或者调用生产方的补偿接口,如退费。

JTA分布式事务

这个没有用过,具体可以参考:

https://www.cnblogs.com/shamo89/p/7306428.html

分表自增ID解决方案

当我们对MySQL进行分表操作后,将不能依赖MySQL的自动增量来产生唯一ID了,因为数据已经分散到多个表中。

应尽量避免使用自增IP来做为主键,为数据库分表操作带来极大的不便。

1.通过MySQL表生成ID

在《关于MySQL分表操作的研究》提到了一种方法:对于插入也就是insert操作,首先就是获取唯一的id了,就需要一个表来专门创建id,插入一条记录,并获取最后插入的ID。代码如下:

CREATE TABLE `ttlsa_com`.`create_id` (
`id` BIGINT( 20 ) NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE = MYISAM

这种方法效果很好,但是在高并发情况下,MySQL的AUTO_INCREMENT将导致整个数据库慢。如果存在自增字段,MySQL会维护一个自增锁,innodb会在内存里保存一个计数器来记录auto_increment值,当插入一个新行数据时,就会用一个表锁来锁住这个计数器,直到插入结束。如果是一行一行的插入是没有问题的,但是在高并发情况下,那就悲催了,表锁会引起SQL阻塞,极大的影响性能,还可能会达到max_connections值。

2.队列方式

使用队列服务,如redis、memcacheq等等,将一定量的ID预分配在一个队列里,每次插入操作,先从队列中获取一个ID,若插入失败的话,将该ID再次添加到队列中,同时监控队列数量,当小于阀值时,自动向队列中添加元素。

这种方式可以有规划的对ID进行分配,还会带来经济效应,比如QQ号码,各种靓号,明码标价。如网站的userid, 允许uid登陆,推出各种靓号,明码标价,对于普通的ID打乱后再随机分配。

3.SnowFlake算法生成分布式id



特点: ①递增 ,②保证69年不重复,③每一毫秒生产4096个序列号。

美团SnowFlake算法开源地址:https://github.com/MrSorrow/Leaf

Gitee地址

Spring事物:https://gitee.com/zhuayng/foundation-study/blob/develop/SpringBootDemo/src/test/java/com/yxkj/springbootdemo/SpringbootdemoApplicationTestPropagationBehavior.java

SnowFlake算法:https://gitee.com/zhuayng/foundation-study/blob/develop/JavaBasis/Tools/src/main/java/com/yxkj/javabasistools/tools/idtools/SnowFlake.java

Spring事物的更多相关文章

  1. MyBatis6:MyBatis集成Spring事物管理(下篇)

    前言 前一篇文章<MyBatis5:MyBatis集成Spring事物管理(上篇)>复习了MyBatis的基本使用以及使用Spring管理MyBatis的事物的做法,本文的目的是在这个的基 ...

  2. spring事物的传播行为

    1.spring事物的传播行为,主要是用来解决业务层拥有事物的方法,相互调用的问题. 2.声明事物, 在代码执行前,开启事务.代码执行完,提交事务 3.spring并没有提供事务具体的处理,而只是调用 ...

  3. Spring 事物Transaction

    日常开发中Spring 为我们提供了两种事物的定义方式 XML 配置 方式 :这种方式配置起来比较麻烦,但后期比较好进行维护 注解方式:配置起来比较方便,也是日常开发常用的: 我们这里进行第二种注解的 ...

  4. Spring事物管理--相关要点及配置事物管理器

    事务的四大特征 1.原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做 2.一致性:数据不会因为事务的执行而遭到破坏 3.隔离性:一个事物的执行,不受其他事务的干扰,即并 ...

  5. spring事物深入了解

    1.问题 1.以前对事物的了解只是停留在声明式事物,配置xml,或使用注解,事物的传播行为也只用过REQUIRED和SUPPORTS,可以说对事物的了解很模糊. 2.直到在开发中遇到问题.. 问题的描 ...

  6. spring 事物的一些理解

    推荐一个我认为Spring事物写得很好的文章. 文章链接:http://www.codeceo.com/article/spring-transactions.html  文章作者:码农网 – 吴极心 ...

  7. 数据库事物 jdbc事物 spring事物 隔离级别:脏幻不可重复读

    1.数据库事物: 事物的概念 a给b打100块钱的例子 2.jdbc事物: 通过下面代码实现 private Connection conn = null; private PreparedState ...

  8. Spring 事物传播特性

    Spring 事物传播特性 这是Spring官方的定义 一共有7种 摘自源码省略了一部分 public interface TransactionDefinition { int PROPAGATIO ...

  9. spring 事物管理没起到作用

    今天在做项目的时候发现配置的spring 事物管理没起到作用.可是配置又是依据官网配置的,不可能会错.最后发现使mysql的问题 普通情况下,mysql会默认提供多种存储引擎,你能够通过以下的查看: ...

  10. java陷阱之spring事物管理导致锁无效

    模拟锁情况无效 1.创建一个表 SET NAMES utf8mb4; ; DROP TABLE IF EXISTS `demo`; CREATE TABLE `demo` ( `id` ) NOT N ...

随机推荐

  1. Direct and Indirect Effects

    目录 概 主要内容 CDE NDE NIE TDE, TIE, PDE, PIE Judea Pearl. Direct and indirect effects. In Proceedings of ...

  2. BL8810|USB2.0高速闪存读卡器|BL8810芯片

    BL8810是由台湾旺玖半导体推出的一款USB2.0 SD/MMC闪存读卡器单芯片.支持USB2.0高速传输,并符合通用串行总线规范.该芯片集成了一个高速的8051微处理器和一个最好的数据引擎,它的引 ...

  3. CS5218DP转HDMI转接方案|CS5218说明|CS5218

    Capstone CS5218是一款单端口HDMI/DVI电平移位器/中继器,具有重新定时功能.它支持交流和直流耦合信号高达3.0-Gbps的操作与可编程均衡和抖动清洗.它包括2路双模DP电缆适配器寄 ...

  4. 网络划分和各层协议以及webservice 浅谈

    最近在公司做一些和其他外部系统接口调用的工作,遇到一些网络传输的问题,趁周末的时间记录.整理一下. 提到网络我们不得不提网络的分层架构: 我们通常听到 网络七层架构/五层架构/四层架构,但是不了解很容 ...

  5. Java工程编码格式由GBK转化成utf-8(编码格式互转)

    在写项目的过程中我发现有的地方编码格式被设置成了 gbk 如果用eclipse等工具直接改回utf-8编码格式则会出现乱码. 下载:https://download.csdn.net/download ...

  6. nssm常用命令(在Windows系统下安装服务的工具)

    nssm install servername //创建servername服务 nssm start servername //启动服务 nssm stop servername //暂停服务 ns ...

  7. 【MySQL作业】多字段分组和 having 子句——美和易思分组查询应用习题

    点击打开所使用到的数据库>>> 1.按照商品类型和销售地区分组统计商品数量和平均单价,并按平均单价升序显示. -- 按照商品类型和销售地区分组统计商品数量和平均单价,并按平均单价升序 ...

  8. Jenkins安装、配置与说明

    Jenkins是一个开源的.提供友好操作界面的持续集成(CI)工具,主要用于持续.自动的构建/测试软件项目.监控外部任务的运行. 这么解释很抽象,举个例子,我们开发完一个功能,我们要将项目发布打包好, ...

  9. 发布 vscode 插件 Cnblogs Client For VSCode 预览版

    为了方便大家使用 vscode 发布博文,我们做了一个小插件,今天发布预览版,欢迎大家试用并反馈问题与建议. 插件的英文名称是 Cnblogs Client For VSCode,简称是 vscode ...

  10. CSS基础 定位相关属性的使用方法

    1.相对定位:position:relative: 属性名:position 属性值:relative: 特点:1.相对自己的位置移动 2.配合方位名词移动,如:top.left.right,bott ...