最近在項目中遇到一個問題,在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