Spring @Transactional 事务失效的场景?如何解决?

在项目开发中,如果涉及到多张表操作时,为了保证业务数据的一致性,大家都会采用事务机制;

但是好多小伙伴可能只是简单了解一下,一旦遇到事务失效的情况,便会无从下手,此篇文章给大家整理了一下常见Spring事务失效的场景,希望开发过程尽量避免踩坑,造成时间精力的浪费。

目录

1、失效场景

2、 解决方案

1、非public权限修饰

2、非Spring容器管理的bean

3、注解修饰的方法被类内部方法调用

4、异常类型非RuntimeException

5、捕获异常后,却未抛出异常

6、事务传播行为设置异常

7、数据库存储引擎不支持事务


1、失效场景

  1. @Transactional配置的方法非public权限修饰;

  2. @Transactional所在类非Spring容器管理的bean;

  3. @Transactional所在类中,注解修饰的方法被类内部方法调用;

  4. 业务代码抛出异常类型非RuntimeException,事务失效;

  5. 业务代码中存在异常时,使用try…catch…语句块捕获,而catch语句块没有throw new RuntimeExecption异常;(最难被排查到问题且容易忽略)

  6. 注解@Transactional中Propagation属性值设置错误即Propagation.NOT_SUPPORTED(一般不会设置此种传播机制)

  7. mysql关系型数据库,且存储引擎是MyISAM而非InnoDB,则事务会不起作用(隐藏最深,但基本开发中不会遇到);

2、 解决方案

2.1、非public权限修饰

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

使用代理时,您应该只将@Transactional注释应用于具有公共可见性的方法。如果使用@Transactional注释对受保护的、私有的或包可见的方法进行注释,则不会引发错误,但带注释的方法不会显示配置的事务设置。如果需要注释非公共方法,请考虑使用AspectJ(见下文)。

@Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式。

2.2、非Spring容器管理的bean

基于这种失效场景,有工作经验的大佬基本上是不会存在这种错误的;@Service 注解注释,StudentServiceImpl 类则不会被Spring容器管理,因此即使方法被@Transactional注解修饰,事务也亦然不会生效。

 错误的例子:

import org.springframework.stereotype.Service;

@Service
public interface AreaService {

    //添加地区
	public int addArea(Area area);
}

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;

    //此处的事务将不会生效
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public int addArea(Area area) {
		areaDao.insert(area);
	}

}

正确的例子:

public interface AreaService {

    //添加地区
	public int addArea(Area area);
}


/****************************************分隔线***********************************/


import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    //Spring容器管理的bean
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;

    //此处的事务会生效
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public int addArea(Area area) {
		areaDao.insert(area);
	}

}

2.3、注解修饰的方法被类内部方法调用

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;

    public int check(Area area) {
		addArea(area);
	}

    //此处的事务不会生效
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public int addArea(Area area) {
		areaDao.insert(area);
	}


}

2.4、异常类型非RuntimeException

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;


    //此处的事务不会生效
    @Transactional(propagation = Propagation.REQUIRED)
	public int addArea(Area area) {
		areaDao.insert(area);

        //抛出非RuntimeException类型
        throw new Exception();
	}


}

解决方案:

@Transactional注解修饰的方法,加上rollbackfor属性值,指定回滚异常类型:@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)

2.5、捕获异常后,却未抛出异常

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;


    //此处的事务不会生效
    @Transactional(propagation = Propagation.REQUIRED)
	public int addArea(Area area) {
		try {
           areaDao.insert(area);
        } catch (Exception e) {
            e.printStackTrace();
        }
	}


}

2.6、事务传播行为设置异常

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service    
public class AreaServiceImpl implements AreaService {

	@Autowired
	private AreaDao areaDao;


    //此处的事务不会生效
    @Transactional(propagation = Propagation.NOT_SUPPORTED,rollbackFor = Exception.class)
	public int addArea(Area area) {
		try {
           areaDao.insert(area);
        } catch (Exception e) {
            e.printStackTrace();
        }
	}


}

2.7、数据库存储引擎不支持事务

以MySQL关系型数据为例,如果其存储引擎设置为 MyISAM,则事务失效,因为MyISMA 引擎是不支持事务操作的;

故若要事务生效,则需要设置存储引擎为InnoDB ;目前 MySQL 从5.5.5版本开始默认存储引擎是:InnoDB;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

上一篇:重磅!助你金九银十稳进大厂


下一篇:@Transactional的使用与失效