当前位置: 首页 > news >正文

声明式事务及编程式事务

目录

1.事务说明

2.事务及数据库的隔离级别

3.事务的传播行为

4.声明是事务

5.编程式事务

6.避免长事务的方式


1.事务说明

数据库的事务是一组操作的集合,这些操作要么全部成功,要么全部失败。用于确保事务的一致性及完整性,事务的主要特性可以通过ACID原则来概括

  1. 原子性 (Atomicity)

    事务中的所有操作要么全部完成,要么全部不完成。如果事务中任一操作失败,整个事务都会被回滚,保持数据在执行前的状态。
  2. 一致性 (Consistency)

    事务必须使数据库从一个一致性状态转换到另一个一致性状态。在事务开始之前和结束之后,数据库的完整性约束必须得到满足。
  3. 隔离性 (Isolation)

    并发执行的事务之间应相互独立,一个事务的执行不应影响其他事务的执行。不同的隔离级别会影响事务的并发行为,如未提交读、已提交读、可重复读和串行化等。
  4. 持久性 (Durability)

    一旦事务提交,其结果是永久性的,即使系统发生崩溃,提交的数据也不会丢失。数据库管理系统通常通过日志或其他持久存储机制来实现这一点。

2.事务及数据库的隔离级别

    Read Uncommitted(读未提交)

  • 描述:在这个级别下,一个事务可以读取另一个事务未提交的数据。这意味着事务可以看到其他事务对数据所做的更改,即使这些更改尚未被提交。
  • 优点:性能最高,因为不需要锁定数据。
  • 缺点:可能导致脏读、不可重复读和幻读。

    Read Committed(读已提交)

  • 描述:只有已经提交的事务所做的更改才能被读取。在此级别下,事务在读取数据之前会等待其他事务提交。
  • 优点:避免了脏读问题,但仍可能导致不可重复读和幻读。
  • 缺点:虽然性能比Read Uncommitted略低,但总体上仍然比较高效。

    Repeatable Read(可重复读)

  • 描述:在一个事务中,如果读取某个数据行,那么在该事务结束之前,不管其他事务如何更改该数据行,该行的值将始终保持不变。即使其他事务已经提交了更改,当前事务也看不到这些变化。
  • 优点:防止了脏读和不可重复读,但仍可能发生幻读情况。
  • 缺点:增加了性能开销,尤其是在高并发场景下。

    Serializable(可串行化)

  • 描述:这是最严格的隔离级别,在这个级别下,事务完全隔离。事务的执行就好像所有事务是串行执行的一样,不会有任何干扰。
  • 优点:绝对的一致性,防止所有并发问题,包括脏读、不可重复读和幻读。
  • 缺点:性能最低,因为它可能会导致大量的锁竞争和阻塞。

在Spring中,你可以通过@Transactional注解来设置事务的隔离级别。例如:

import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;@Transactional(isolation = Isolation.REPEATABLE_READ)
public void myTransactionalMethod() {// 业务逻辑
}

脏读:指的是一个事务读取了另一个尚未提交的事务所修改的数据。这种情况可能导致读取到的数据不可靠,因为被读取的数据可能会在后续被回滚,从而使得第一个事务得到的信息变得无效。

不可重复读:它指的是在同一事务中,对同一数据的两次读取可能得到不同的结果。这种情况通常发生在以下场景中:

  1. 事务A读取了某个数据项(例如,价格)。
  2. 事务B在事务A的读取后对该数据项进行了修改。
  3. 事务A再次读取同一数据项时,可能会发现数据已被事务B修改过,从而得到不同的结果。

 幻读:指在同一事务中,反复执行相同的查询操作时,结果集会出现不同的数据情况。具体来说,当一个事务在读取数据后,另一个事务对数据库进行了插入或删除操作,导致第一个事务再次执行相同查询时,能够看到新插入的行(或缺失被删除的行),这就称为幻读

3.事务的传播行为

        描述了当一个事务调用另一个事务时,如何处理事务边界和事务上下文。常见的传播行为包括:

  • REQUIRED:如果存在当前事务,则加入该事务;如果没有,则创建新事务。
  • REQUIRES_NEW:总是创建一个新的事务,如果存在当前事务则挂起它。
  • NESTED:支持嵌套事务,允许在当前事务中开启一个子事务。
  • MANDATORY:要求当前操作必须在一个已有的事务中进行。如果存在当前事务,则加入该事务;如果没有,则抛出异常
  • SUPPORTS:如果有当前事务则参与,否则以非事务方式执行。
  • NOT_SUPPORTED:不支持事务,如果存在事务则挂起。
  • NEVER:不支持事务,若存在事务则抛出异常。

4.声明是事务

声明式事务通过Transactional注解进行实现,是基于AOP的,本质是在方法执行前后进行拦截,在方法执行前开启事务,在方法之后后按照不同的情况进行事务的提交和回滚。

Transactional注解的参数说明

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
//当配置了多个事务管理器时,指定选择哪一个事务管理器@AliasFor("transactionManager")String value() default "";
//和上个参数一致@AliasFor("value")String transactionManager() default "";String[] label() default {};
//设置事务的传播行为Propagation propagation() default Propagation.REQUIRED;
//设置事务的隔离级别Isolation isolation() default Isolation.DEFAULT;
//事务的超时时间int timeout() default -1;
//和上面一样String timeoutString() default "";
//指定事务是否为只读事务,为了忽略那些不需要事务的方法,比如读取数据boolean readOnly() default false;
//执行触发回滚的异常类型Class<? extends Throwable>[] rollbackFor() default {};
//和上面一样String[] rollbackForClassName() default {};
//抛出指定的异常,不会滚事务Class<? extends Throwable>[] noRollbackFor() default {};
//和上面一样String[] noRollbackForClassName() default {};
}

优点:

不需要通过编程的方法管理事务,即不要进行事务手动开启,提交及回滚,直接在需要添加事务的方法上使用@Transactional注解即可

缺点:

最细粒度只能是方法级别,无法像编程事务可以作用到代码块级别

事务失效的几种情况:

  • 使用在非public方法上会导致事务失效
  • 同一个类中,一个无事务的方法内通过this方式调用有事务的方法会导致事务失效
  • 异常被捕捉了导致事务失效

5.编程式事务

编程式事务允许开发者在代码中明确地控制事务的开始、提交和回滚。使用Spring的事务管理器,你可以通过TransactionTemplate或直接使用PlatformTransactionManager来实现编程式事务管理。

PlatformTransactionManager示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;   @Overridepublic int insertConfig() {DefaultTransactionDefinition def = new DefaultTransactionDefinition();// 设置事务的传播机制def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);// 设置事务的隔离级别def.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_REPEATABLE_READ);// 开始事务TransactionStatus status = transactionManager.getTransaction(def);try {SysConfig config;for (int i = 0; i < 5; i++) {config = new SysConfig();config.setConfigName("配置" + i);configMapper.insertConfig(config);if (i == 2) {throw new RuntimeException();}}// 提交事务transactionManager.commit(status);} catch (Exception e) {// 回滚事务transactionManager.rollback(status);throw e;}return 1;}

TransactionTemplate示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;  public int insertConfig2() {transactionTemplate.execute(status -> {try {SysConfig config;for (int i = 0; i < 5; i++) {config = new SysConfig();config.setConfigName("配置" + i);configMapper.insertConfig(config);if (i == 2) {throw new RuntimeException();}}} catch (Exception e) {status.setRollbackOnly();throw e;}return 1;});return 1;}

通过编程式事务可以手动控制事务的范围 

6.避免长事务的方式

①不要在整个大方法上添加Transactional注解,将增删改操作放在一个独立的方法,在这个方法上使用Transactional注解,注意注解失效的情况。

②使用编程式事务,在需要的代码中进行事务控制

③事务中避免远程调用,通过建立重试补偿机制,保证数据的一致性

④事务中避免一次处理太多的数据,可以进行分批处理,处理成功直接提交。这种情况出现异常无法对所有的数据进行回滚,需要将异常的数据返回至前端,或者通过钉钉的方式进行提醒,让用户对异常的数据进行二次处理。例如一次导入大批量数据的情况

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 数据在内存中的存储(了解大小端字节序浮点数在内存中存储)详细~
  • zabbix实战-磁盘空间告警
  • 华为鸿蒙Core Vision Kit 骨骼检测技术
  • 构建第一个Spring项目
  • 黑神话悟空什么配置可以玩?什么样的游戏本配置可以畅玩《黑神话:悟空》?黑神话悟空电脑配置推荐
  • WEB之文件上传
  • 华为M60首次降价,消费回暖能延续?
  • 【FreeRTOS】队列实验-多设备玩游戏(旋转编码器)
  • SQL 时间盲注 (injection 第十五关)
  • java.sql.SQLException: txn too large, size: 104857606.
  • SQLALchemy 分组过滤、子查询
  • QT网络编程: 实现UDP通讯设置
  • java使用itext 直接生成pdf
  • 2025ICASSP Author Guidelines
  • 宠物空气净化器推荐买吗?清除浮毛的效果好吗
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • Redis中的lru算法实现
  • tab.js分享及浏览器兼容性问题汇总
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 从0实现一个tiny react(三)生命周期
  • 服务器从安装到部署全过程(二)
  • 后端_ThinkPHP5
  • 记一次用 NodeJs 实现模拟登录的思路
  • 坑!为什么View.startAnimation不起作用?
  • 理清楚Vue的结构
  • 区块链将重新定义世界
  • 听说你叫Java(二)–Servlet请求
  • 学习HTTP相关知识笔记
  • 译有关态射的一切
  • 云大使推广中的常见热门问题
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (007)XHTML文档之标题——h1~h6
  • (1)(1.11) SiK Radio v2(一)
  • (BFS)hdoj2377-Bus Pass
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (转)c++ std::pair 与 std::make
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • .net CHARTING图表控件下载地址
  • .NET Core 版本不支持的问题
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .NET简谈设计模式之(单件模式)
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .NET中使用Redis (二)
  • .vimrc 配置项
  • .vollhavhelp-V-XXXXXXXX勒索病毒的最新威胁:如何恢复您的数据?
  • ?
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?
  • @RequestMapping处理请求异常
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [android] 看博客学习hashCode()和equals()