SpringBoot @Transactional事务回滚实现

一、@Transcational简介
SpringBoot不用单独的去配置事务管理,使用@Transactional即可
@Transactional即声明式事务管理, 建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,更快捷而且简单。推荐使用
@Transactional可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
通常service层事务不生效的原因归纳一下几点:
1.检查你的方法是不是public修饰的。@Tansactional注解只能应用到public修饰的方法上。
2.检查你的异常类型是不是unchecked异常。默认情况下,Spring会对unchecked异常进行事务回滚,也就是默认对RuntimeException()异常或是其子类进行事务回滚。如果是checked异常则不回滚。如空指针异常、算数异常等会被回滚;文件读写、网络问题Spring就没法回滚。如果想check异常也回滚,注解上面写明异常类型即可:@Transactional(rollbackFor = Exception.class)
3.service层进行了try {} catch…操作,但是由于异常被捕获,事务没有回滚。如果想要在service抛异常并且想要事务生效,方案有两种:

方案一:
抛出运行时异常(缺陷是不在catch代码块自定义返回值)

try{
    ....  
}catch(Exception e){
    logger.error("",e);
    throw new RuntimeException;
}

方案二:
手动设置回滚

try{
    ...
}catch(Exception e){
    logger.error("",e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    return false;
}

4.在controller层抛异常,service层不要try{}caich…
5.数据库要支持事务,如果是mysql,要使用innodb引擎,myisam不支持事务

二、事务回滚业务实现
示例场景: 添加用户的同时,要新增用户的角色。在新增用户角色的业务代码故意抛出异常,测试事务回滚

1.controller层

package org.lhj.pro.controller;

import org.lhj.pro.service.impl.UserService; 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/transcational")
public class TranscationalController {
	
	@Autowired
	private UserService userService;
	
	@RequestMapping(value = "/save",method = RequestMethod.POST)
	private Boolean saveUser() {
	
		return	userService.save();

	}
	
}

2.service层,我这里设置的手动回滚

package org.lhj.pro.service.impl;

import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
@Service
public class UserServiceImpl implements UserService {
	
	private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	/**
	 * 添加用户
	 */
	@Override
	public void saveUser() {
		int uid = new Random().nextInt(50) + 1;
		String sql = "insert into t_user values("+uid+",'lucy',18,'2021-01-24 12:00:00')";
		jdbcTemplate.execute(sql);

	}
	
	/**
	 * 添加用户角色
	 */
	@Override
	public void saveUserRole() {
		int i = 1/0;
		String sql = "insert into t_user_role values("+null+",'学生')";
		jdbcTemplate.execute(sql);

	}
	
	/**
	 * 添加方法
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean save() {
		try {
			this.saveUser();
			this.saveUserRole();
			return true;
		} catch (Exception e) {
			logger.error("添加用户失败:",e);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return false;
		}
	
	}
	

}

测试结果: 用户角色添加失败,用户信息同样没有入库

三、常用配置

(1) readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
(2) rollbackFor 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
(3) rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称@Transactional(rollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
(4) noRollbackFor 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
(5) noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})
(6) propagation 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
(7) timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时

四、事务属性

1.事务隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

2.事务传播行为
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

数据库事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。
在这里插入图片描述
3.事务超时
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

4.事务只读属性
只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。
默认为读写事务。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值