Spring声明式事务

1、基本概念

1.1、事务的基本概念

事务:事务是数据库操作的基本单元,逻辑上一组SQL语句要么都执行成功、要么都执行失败!事务有四大特性:原子性、一致性、隔离性、持久性。

原子性:原子是物质的最小组成单位、原子性是只整个事务中所有的SQL语句要么都执行成功,要么都失败!

一致性:事务执行前后数据库中的状态是一致的;例如:A账户有1000元、B账户有1000元;现在A给B转200块钱,执行前总共2000、执行后还是2000。

隔离性:当进行多个事务时,每个事务之间互不造成影响、相互隔离。

持久性:当事务成功提交后,它对数据库中数据的改变就是永久性的。


1.2、Spring两大事务

编程式事务:所谓的编程式事务就是直接在源代码中进行增加手动提交、回滚的代码,有点面向过程编程的味道。

声明式事务:Spring的两大核心就是IOC与AOP,声明式事务是基于AOP实现的;通过增强通知(Advice)切入到方法中,从而达到控制事务的开启、回滚、提交…

区别:编程式事务需要在代码中嵌入事务管理的部分、声明式事务只需要声明在哪里需要进行事务,剩下的交给AOP!



2、声明式事务配置参数

声明式事务配置参数是比较多的,功能非常强大;提供了:propagation(传播行为)、ioslation(隔离级别)、timeout(超时时间)、read-only(是否可读)、rollbackfor(异常回滚)、norollbackfor(异常不回滚)

2.1、传播行为(Propagation)

传播行为:指多个方法方法之间调用,事务是如何进行管理运作。Spring提供了七种事务的传播行为,最常用的是REQUIRED 和 REQUIRED_NEW。
在这里插入图片描述


2.2、隔离级别(Ioslation)
  1. 脏读:一个事务读取到了另一个事务未成功提交的数据;例如:事务A对数据库中的数据进行了修改但是还未提交、此时事务B进行数据读取;但是事务A因为某些原因回滚了,此时B拿到的数据是一个无效数据,也叫脏数据!

  2. 不可重复读:同一个事务内,先后两次读取数据返回结果不一致;例如:事务A第一次读取到数据、事务B修改数据并且成功提交、事务A第二次读取数据;两次读取数据结果不一致。由于事务没有形成隔离导致

  3. 幻读:一个事务读取到另一个事务已经提交的添加或者删除的数据;例如:A事务读取数据、B事务删除(增加)数据,A事务再次读取数据,发现多出一些新的数据,像出现了幻觉一样。

  4. 幻读与不可重复度的区别:不可重复度强调的是修改数据;幻读强调的是添加、删除数据。

  5. 总结:脏读是致命的操作,因为拿到的数据是无效数据;而不可重复度与幻读是一种现象,只是先后读取不一致的问题,但是数据是有效的(其他事物成功提交)!

为了解决这些问题或现象,Spring提供了4种隔离级别;隔离级别越高,性能越差;一般会使用Repeatable read(可重复读级别)。
在这里插入图片描述

2.3、其他参数
  1. Timeout:设置事物多长时间内进行提交,如果超过设定时间进行回滚。设置值为-1表示永不超时,其他非负整数值单位为秒;例如:timeout = 5表示5秒后如果为成功提交则自动回滚!

  2. read-only:设置是否只有读取的权限,一般使用在专门查询的方法上;当值为false表示可以进行CRUD、值为true只能进行读!

  3. rollbackfor:设置事务发生哪些异常时进行回滚!

  4. norollbackfor:设置事务发生哪些异常时不进行回滚!



3、XML配置声明式事务

首先要进行数据源和Jdbc执行器的配置,然后在声明事务!声明式事务是以AOP的形式横向切入到方法中的,业务部分只需要专注于业务即可。

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 配置增强类 -->
<tx:advice id="transAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    	<!-- transfer方法进行事务 -->
        <tx:method name="transfer" propagation="REQUIRED" timeout="30" read-only="false" isolation="REPEATABLE_READ"/>
        <!-- 所有方法进行事务,传播行为默认REQUIRED,隔离级别默认RR、超时-1、是否只读默认false... -->
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!-- aop配置 -->
<aop:config>
    <!-- 定义切入点 -->
    <aop:pointcut id="pt" expression="execution(* com.service.AccountService.transfer(..))"/>
    <!-- 将增强类注入到切入点上 -->
    <aop:advisor advice-ref="transAdvice" pointcut-ref="pt"/>
</aop:config>


4、注解方式配置

注解方式配置首先需要在xml中开启注解扫描、注解支持、事务注解的驱动。当然在完全脱离xml时也可以在配置类上以注解的形式进行手动的开启这些。

<!-- 注解扫描与支持 -->
<context:component-scan base-package="com.*"/>
<context:annotation-config/>

<!-- 事务注解驱动支持 -->
<tx:annotation-driven/>

然后在需要事务的Dao层或者Service层进行配置

@Service("accountService")
@Transactional(
        propagation = Propagation.REQUIRED,
        timeout = 30,
        isolation = Isolation.REPEATABLE_READ,
        readOnly = false
)
public class AccountService {

	@Autowired
	private AccountMapper accountMapper;
	
	public void transfer() {
	    HashMap<Object, Object> map = new HashMap<>();
	    map.put("money", 100);
	    map.put("id", "2");
	    int j = accountMapper.substractMoney(map);
	    int sum = 10 / 0;
	    map.put("id", "1");
	    int i = accountMapper.addMoney(map);
	    System.out.println("i = " + i + ", j = " + j);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值