Spring事务的七种传播方式

Spring事务

如果你作为一个开发者,不开事务就增删改,那我估计一天都活不下来就改走人了,事务很重要,简单来说事务就是连续一组的sql操作,一组动作都完成才能提交,但凡是一个环节出了异常那就得回滚到最初的状态
传播方式则主要是指多个事务同时存在时,Spring如何处理事务,它们是否需要在同一个事务中运行;一个有事务的方法被另外有事务的方法调用时,这个事务应该如何运行;例如

methodA() { // 有事务
 update; 
 ServiceB.methodB(); // 又调用了另一个有事务的方法 异常;
 }
methodB() { // 事务 
update;
}

7种传播方式

在这里插入图片描述

开事务

Spring容器中配置用注解的方式开事务,xml写<bean>我下面会说

<tx:annotation-driven transaction-manager="transactionManager" />

1 REQUIRED

REQUIRED:表示如果当前存在一个事务,则加入该事务,否则将新建一个事务;这个是Spring事务默认传播行为

测试

	@Transactional(propagation = Propagation.REQUIRED,
		isolation = Isolation.DEFAULT)
	public int incr(int balance, int id) {
		//传播方式request
		int result = studentMapper.updateBalance(balance, id);
		 //新事务
		 studentService.decr(-100, 2);
		 //制造异常引起incr这个事务回滚
		 int i = 1/0;
		return result ;
	}
	@Transactional(propagation = Propagation.REQUIRED,
			isolation = Isolation.DEFAULT,
			rollbackFor = Throwable.class)
	public int decr(int balance, int id){
		int result = studentMapper.updateBalance(balance, id);
		 return result ;
	}

测试结果是两个方法对应的操作都不起作用,decr加入到了incr这个事务中,incr回滚导致decr也回滚


2 REQUIRES_NEW

表示不管是否存在事务,都创建一个新的事务,原来的事务挂起,新的事务执行完毕,继续执行老的事务;

测试

和刚才代码几乎一样,我只是把decr的传播方式改成了REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRED,
		isolation = Isolation.DEFAULT)
	public int incr(int balance, int id) {
		//传播方式request
		int result = studentMapper.updateBalance(balance, id);

		 //新事务
		 studentService.decr(-100, 2);
		 //制造异常
		 int i = 1/0;
		return result ;
	}

	/** 转出 */
	@Transactional(propagation = Propagation.REQUIRES_NEW,
			isolation = Isolation.DEFAULT,
			rollbackFor = Throwable.class)
	public int decr(int balance, int id) {
		int result = studentMapper.updateBalance(balance, id);
		 return result ;
	}

而结果是decr这个事务不会被incr影响,最终导致"增加"这个事务回滚,"减少"这个事务会正常提交


3 SUPPORTS

表示如果当前存在事务,就加入该事务;如果当前没有事务,那就不使用事务;

测试

	/** 转入 */
	@Override
	public int incr(int balance, int id) {//没有事务
		//传播方式request
		int result = studentMapper.updateBalance(balance, id);

		 //新事务
		 studentService.decr(-100, 2);
		 int i = 1/0;
		return result ;
	}

	/** 转出 */
	@Transactional(propagation = Propagation.SUPPORTS,
			isolation = Isolation.DEFAULT,
			rollbackFor = Throwable.class)
	public int decr(int balance, int id) /*throws SQLException */{
		int result = studentMapper.updateBalance(balance, id);

		//throw new SQLException("SQL异常");
		 return result ;
	}

结果是incr 和 decr都没有事务,即使报了异常,也都操作成功了,反之我们给incr设上事务

测试二

	@Transactional(propagation = Propagation.REQUIRED,
					isolation = Isolation.DEFAULT
	)
	public int incr(int balance, int id) {
		//传播方式request
		int result = studentMapper.updateBalance(balance, id);

		 //新事务
		 studentService.decr(-100, 2);
		 int i = 1/0;
		return result ;
	}

	/** 转出 */
	@Override
	@Transactional(propagation = Propagation.SUPPORTS,
			isolation = Isolation.DEFAULT,
			rollbackFor = Throwable.class)
	public int decr(int balance, int id) /*throws SQLException */{
		int result = studentMapper.updateBalance(balance, id);

		//throw new SQLException("SQL异常");
		 return result ;
	}

结果是decr进入了incr这个事务,两者都回滚了,对数据库没有影响


4 NOT_SUPPORTED

表示不使用事务;如果当前存在事务,就把当前事务暂停,以非事务方式执行;

测试

	/** 转入 */

	public int incr(int balance, int id) {
		//传播方式request
		int result = studentMapper.updateBalance(balance, id);

		 //新事务
		 studentService.decr(-100, 2);
		 int i = 1/0;
		return result ;
	}

	/** 转出 */
	@Transactional(propagation = Propagation.NOT_SUPPORTED,
			isolation = Isolation.DEFAULT,
			rollbackFor = Throwable.class)
	public int decr(int balance, int id) /*throws SQLException */{
		int result = studentMapper.updateBalance(balance, id);

		//throw new SQLException("SQL异常");
		 return result ;
	}

测试结果是两者都没了事务,抛异常没有影响


5 MANDATORY

表示必须在一个已有的事务中执行,如果当前没有事务,则抛出异常;

测试

假设我不在一个事务中执行,而且我把1/0这个异常排了看看效果

	/** 转入 */
	public int incr(int balance, int id) {
		//传播方式request
		int result = studentMapper.updateBalance(balance, id);

		 //新事务 会出异常
		 studentService.decr(-100, 2);
		return result ;
	}

	/** 转出 */
	@Transactional(propagation = Propagation.MANDATORY,
			isolation = Isolation.DEFAULT,
			rollbackFor = Throwable.class)
	public int decr(int balance, int id) /*throws SQLException */{
		int result = studentMapper.updateBalance(balance, id);

		//throw new SQLException("SQL异常");
		 return result ;
	}

测试的结果是,因为incr事务被关了,所以不管下面的代码异常与否,incr会影响数据库,因为事务被decr关了,而它自己会抛出异常导致不执行本身的操作


6 NEVER:

表示以非事务方式执行,如果当前存在事务,则抛出异常;

测试

正好和MANDATORY相反,我们这次把它放在一个事务中看效果,而且它既然自己抛异常我们把那个 1/0给删了

	/** 转入 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
	public int incr(int balance, int id) {
		//传播方式request
		int result = studentMapper.updateBalance(balance, id);
		 //新事务
		 studentService.decr(-100, 2);
		return result ;
	}

	/** 转出 */
	@Override
	@Transactional(propagation = Propagation.NEVER,
			isolation = Isolation.DEFAULT,
			rollbackFor = Throwable.class)
	public int decr(int balance, int id) /*throws SQLException */{
		int result = studentMapper.updateBalance(balance, id);

		//throw new SQLException("SQL异常");
		 return result ;
	}

测试结果是 两个方法都不会对数据库造成影响,因为decr由于抛异常导致incr回滚,而他自己也没有顺利执行所以不会影响数据库


7 NESTED:

这个是嵌套事务,如果当前存在事务,则在嵌套事务内执行;如果当前不存在事务,则创建一个新的事务;
嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套事务回滚;

-可以理解为:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作。


配置文件开事务

写在SpringRoot容器中

	<tx:advice id="tx-advice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" />
			<tx:method name="update*" />
			<tx:method name="delete*" />
			<tx:method name="transfer" isolation="DEFAULT"
					   propagation="REQUIRED" rollback-for="Throwable" />
			<tx:method name="incr" propagation="REQUIRED" />
			<tx:method name="decr" propagation="NESTED" />
			<tx:method name="query*" read-only="true" />
		</tx:attributes>
	</tx:advice>

总结

两种开事务的方式,和七种传播方式你学会了吗

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

商朝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值