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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章