Spring事物(一)----基本概论

本文深入解析Spring事务管理,涵盖事务的基本概念、ACID特性、隔离级别、传播行为及管理方式,探讨编程式与声明式事务管理的区别,并详解@Transactional注解的使用与自动提交模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是事物

    事务是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败。

    简单举例,假设有用户A,B的账户各有余额100元,A给B转100元,转钱的结果:第一种结果转账成功,A账户的余额为0元,B账户的余额为200元;第二种结果转账失败,A账户的余额为100元,B账户的余额为100元;事物就是用来保证在转账的过程中不会出现A账户的余额为100元,B账户的余额为200元。或是A账户的余额为0元,B账户的余额为100元。

事务特性(ACID)

原子性 (Atomicity) :事务的不可分割性
    A给B转账100元,A-100成功,B+100成功;A-100失败,B+100失败;两个操作必须保持一致,不可再分。

一致性 (Consistency):事务的执行的前后数据的完整性保持一致
    A,B账户各100元,A给B转账100元,不管成功或者失败,A,B账户合计都为200元;此为强一致性; 题外话(最终一致性,有兴趣的话可以看看分布式事物),可以在某个时间窗口账户共计不为200元,但是最终结果为200元。

隔离性 (Isolation) :一个事务执行的过程中,不应该受到其他事务的干扰
    A给B转账100元过程中,叫做事物1,有个操作查询A余额,叫做事物2,事物2查询A余额的只会0元或者100元,也就是说只能查询到事物1执行事物之前或者之后的状态,不会查询到事情1执行过程中的中间状态。

持久性 (Durability) :事务一旦结束,数据就持久到数据库
    A,B账户各100元,A给B转账100元,A-100成功,B+100成功;A的账户变成0元,B的账户变成200元,最终会在数据库做数据持久化。

事物隔离级别

如果不考虑事物隔离性,多个事物在执行情况下将会出现如下安全性问题:

1.脏读 : 一个事务读到了另一个事务的未提交的数据 。
    事物1做update操作未提交,事物2做select操作,此时如果事物1回滚,那么事物2就读取了事物1操作后的结果。导致脏读。

2.不可重复读 : 一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.。
    事物1第一次做select操作,此时事物2做update操作并提交,事物1第二次做select操作,发现和第一次查询的结果不一样。

3.虚幻读 : 一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致。
    事物1做update操作将账户的余额全部改为0,并进行第一次select操作,发现余额都为0,此时事物2插入一条余额为100元的记录,事物1做第二次操作,发现账户还有大于0的数据,有点虚幻的感觉,明明已经全部余额改为0了。

 **那么问题来了,如何来解决上述情况呢,其实很简单我们通过设置事务隔离级别**

事务隔离级别(5种)
DEFAULT
默认的隔离级别,使用数据库默认的事务隔离级别.

未提交读(Read Uncommitted)
最低的隔离级别,如果一个事务已开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据。脏读,不可重复读,虚读都有可能发生 。

已提交读(Read Committed)
读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行,避免脏读。但不可重复读和虚读有可能发生。

可重复读(Repeatable Read)
读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务,相当于程序select…for update动作,可避免脏读和不可重复读,但虚读有可能发生。

串行化读(Serializable)
事务串行执行,不能并发执行。相当于每次执行之前先锁全表,虽可避免以上所有读问题,但性能低下。

Mysql 默认:可重复读
Oracle 默认:读已提交

事务的传播行为

PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常

事务的管理方式

spring支持编程式事务管理和声明式事务管理两种方式。
1.编程式事务管理使用TransactionTemplate或者直接使用底层PlatformTransactionManager。

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(jdbcTemplate.getDataSource());
TransactionStatus status = transactionManager.getTransaction(def);
		try {
			String insertSql = this.getInsertSql(newItems);
			List<Object[]> batchArgs = this.getInsertValueList(newItems);
			jdbcTemplate.batchUpdate(insertSql, batchArgs);
		} catch (Exception e) {
				// 事务回滚,一条条执行
				transactionManager.rollback(status);
				throw e;
		}
		transactionManager.commit(status);

2.声明式事务管理也有两种常用的方:

一种是基于tx和aop名字空间的xml配置文件

<!-- 1.声明式事务,基于tx和aop名字空间的xml配置文件 -->
    <bean id="web_transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<tx:advice id="web_txAdvice" transaction-manager="web_transactionManager">
		<tx:attributes>
		   <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class"/>
		    <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class" />
		    <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="BusinessException.class"/>
		    <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
     		<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
      		<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
      		<tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
		</tx:attributes>
	</tx:advice>
    <aop:config>
        <aop:pointcut id="interceptorPointCuts"
                      expression="execution(* com.kook.web.base.dao.*.*(..))" />
        <aop:advisor advice-ref="web_txAdvice"
                     pointcut-ref="interceptorPointCuts" />
    </aop:config>

一种就是基于@Transactional注解。

<!--2.声明式事务,基于@Transactional注解-->
    <tx:annotation-driven transaction-manager="txManager" />
     <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="dataSource" />
     </bean>

@Transactional注解

@Transactional属性

属性类型描述
valueString指定使用的事务管理器,可选的
propagationenum: Propagation可选的事务传播行为设置(7种)
isolationenum: Isolation可选的事务隔离级别设置(5种)
readOnlyboolean读写或只读事务,默认读写
timeoutint事务超时时间设置(单位秒)
rollbackForClass对象数组,继承自Throwable导致事务回滚的异常类数组
rollbackForClassName类名数组,继承自Throwable导致事务回滚的异常类名字数组
noRollbackForClass对象数组,继承自Throwable不会导致事务回滚的异常类数组
noRollbackForClassName类名数组,必须继承自Throwable不会导致事务回滚的异常类名字数组

@Transactional用法
1.@Transactional 可以用于接口、接口方法、类以及类方法上,一般情况不要在接口和接口方法上使用该注解
2.@Transactional 注解只能被应用到 public 方法上,如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,注解将会被忽略,也不会抛出任何异常。
3.默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为。

自动提交模式

默认情况下,数据库处于自动提交模式,即autocommit=true,当你执行一组sql语句, 此时每条sql语句都处于一个单独的事务中,这是数据库最小粒度事物,如果sql执行成功,数据库将自动提交,如果失败,则回滚。而事物是将一组sql语句处与一个事物中,因此必须在开启事物的时候,关闭数据库自动提交模式,即autocommit=false。

DataSourceTransactionManager的doBegin方法片段

			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
			// so we don't want to do it unnecessarily (for example if we've explicitly
			// configured the connection pool to set it already).
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值