service 代碼
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void multiUpdateUser(User user1, User user2) {
this.updateUser(user1);
}
@Override
@Transactional
public void updateUser(User user) {
int count = userMapper.updateByPrimaryKeySelective(user);
System.out.println(count);
int i = 1 / 0;
}
}
問題:controller 里面調(diào)用 multiUpdateUser() 方法,則updateUser 方法的事務(wù)失效(即使出現(xiàn)異常也沒有回滾)器躏,事務(wù)傳播行為用的默認(rèn)的 REQUIRED牺六,即支持當(dāng)前事務(wù),如果沒有事務(wù)就開啟事務(wù),這里卻沒有開啟惨撇。
原因:
@Transactional 注解基于AOP實(shí)現(xiàn)胎撤,所以 updateUser() 被其他類調(diào)用時是通過代理對象來調(diào)用的晓殊,在代理對象的增強(qiáng)方法中開啟事務(wù),而沒有注解的 multiUpdateUser() 方法被調(diào)用是原有的對象調(diào)用的伤提,此時在 multiUpdateUser() 方法中調(diào)用 updateUser() 方法巫俺,則 updateUser() 就是直接被原有對象調(diào)用,而沒有被代理對象調(diào)用肿男,也就不會被增強(qiáng)介汹,不會開啟事務(wù),即事務(wù)失效舶沛。
解決方案:
手動獲取 Spring 中的代理對象(即 Spring 創(chuàng)建的 bean)嘹承,通過代理對象去調(diào)用有事務(wù)注解的方法(本例updateUser() ),首先創(chuàng)建工具類如庭,通過 ApplicationContex 獲取 bean
/**
SpringUtils 工具類
*/
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
}
/**
* 通過 class 獲取 Bean
*/
public static <T> T getBean(Class<T> clazz) {
return SpringUtils.applicationContext.getBean(clazz);
}
}
service 中的代碼改造如下
public void multiUpdateUser(User user1, User user2) {
SpringUtils.getBean(UserService.class).updateUser(user1);
}
至此叹卷,事務(wù)就生效了。