Spring service调用当前类方法导致事务不生效

最近在项目中遇到一个问题,在service类中调用当前类的一个方法,没有开启事务,如下:

@Service("userService")
public class UserServiceImpl implements UserService{
	
	@Autowired
	private UserMapper userMapper;	

	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚	
	@Transactional
	@Override
	public void addUser() {
		User user1 = new User();
		user1.setUserName("zhaoliu21");
		user1.setName("赵柳21");
		user1.setPassword("12323");
		userMapper.insert(user1);				
		this.updateUser(user1);  //this.updateUser()调用的并不是spring的代理对象,所以没有事务		
	}

	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@Override
	public void updateUser(User user) {
		System.out.println("************updateUser  开始**************");
		User user1 = new User();
		user1.setId(46L);
		user1.setName("王武");
		userMapper.updateUserById(user1);
		System.out.println("************updateUser  结束**************");
	}

}

如上代码,在addUser()中调用this.updateUser()时,由于updateUser()上配置了事务传播属性Propagation.REQUIRES_NEW,表示重新开启一个新事务,但是我们在执行后,通过日志发现却没有开启新事务。
原因是Spring的事务是通过aop管理的,基于aop生成代理对象开启事务。所以在同一个类中直接调用方法,并没有使用到代理对象。

解决方法有三种,如下:
1.在service类中注入自己本身,然后调用该类方法:

@Service("userService")
public class UserServiceImpl implements UserService{
		
	@Autowired
	private UserMapper userMapper;
	@Autowired
	private UserService userService;
	
	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚
	@Transactional
	@Override
	public void addUser() {
		User user1 = new User();
		user1.setUserName("zhaoliu21");
		user1.setName("赵柳21");
		user1.setPassword("12323");
		user1.setSex(1);
		userMapper.insert(user1);
		userService.updateUser(user1);
	}

	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@Override
	public void updateUser(User user) {	
		System.out.println("************updateUser  开始**************");
		User user1 = new User();
		user1.setId(46L);
		user1.setName("王武");
		userMapper.updateUserById(user1);
		System.out.println("************updateUser  结束**************");
	}
}

2.若是Springboot工程,则可以用注解开启cglib代理,开启exposeProxy=true,暴露代理对象

@EnableAspectJAutoProxy(exposeProxy=true)
@SpringBootApplication
@EnableTransactionManagement
@MapperScan("com.bms.mapper")
public class Application {
	public static void main(String[] args) {
		ApplicationContext ac = SpringApplication.run(Application.class, args);
	}
}

或是用XML配置文件配置:

<aop:aspectj-autoproxy expose-proxy="true"/>

这样就可以在代码中调用了:

@Service("userService")
public class UserServiceImpl implements UserService{
		
	@Autowired
	private UserMapper userMapper;
	
	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚
	@Transactional
	@Override
	public void addUser() {
		User user1 = new User();
		user1.setUserName("zhaoliu21");
		user1.setName("赵柳21");
		user1.setPassword("12323");
		user1.setSex(1);
		userMapper.insert(user1);
		((UserService)AopContext.currentProxy()).updateUser(user1);
	}

	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@Override
	public void updateUser(User user) {	
		System.out.println("************updateUser  开始**************");
		User user1 = new User();
		user1.setId(46L);
		user1.setName("王武");
		userMapper.updateUserById(user1);
		System.out.println("************updateUser  结束**************");
	}
}

3.通过代码获取spring容器中的bean,然后调用:

@Component
public class SpringContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        assertApplicationContext();
        return applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName) {
        assertApplicationContext();
        return (T) applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> requiredType) {
        assertApplicationContext();
        return applicationContext.getBean(requiredType);
    }

    private static void assertApplicationContext() {
        if (SpringContextHolder.applicationContext == null) {
            throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
        }
    }

}
@Service("userService")
public class UserServiceImpl implements UserService{
		
	@Autowired
	private UserMapper userMapper;
	
	//默认情况下Spring的声明式事务对所有的运行时异常进行回滚
	@Transactional
	@Override
	public void addUser() {
		User user1 = new User();
		user1.setUserName("zhaoliu21");
		user1.setName("赵柳21");
		user1.setPassword("12323");
		user1.setSex(1);
		userMapper.insert(user1);
		SpringContextHolder.getBean(UserService.class).updateUser(user1);
	}

	@Transactional(propagation=Propagation.REQUIRES_NEW)
	@Override
	public void updateUser(User user) {	
		System.out.println("************updateUser  开始**************");
		User user1 = new User();
		user1.setId(46L);
		user1.setName("王武");
		userMapper.updateUserById(user1);
		System.out.println("************updateUser  结束**************");
	}
}

阿里云拼团2折起:https://www.aliyun.com/acts/hi-group-buying?userCode=litzwg4e
最高2000代金券:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=litzwg4e

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值