Spring事务注意点
service中未带事务的方法调用了自身带事务的方法时,按下面写法数据是提交不了的。
public String getMaxSystemVersionNo() {
SystemVersion version = systemVersionDao.getMaxSystemVersion();
version.setUpgradeDate(new Date());
this.updateSystemVersion(version);
return version.getVersion();
}
public int updateSystemVersion(SystemVersion version) {
return systemVersionDao.updateSystemVersion(version);
}
原因:因为get开头的方法在spring事务配置中是不带任何事务的,所以调用自身带事务方法时也是以非事务的方式运行。如果是调用其他service中带事务方法时是可以开启事务的。
解决方法一:
下面写法可以使不带事务的方法变为带事务,能提交数据。
public String getMaxSystemVersionNo() {
SystemVersion version = systemVersionDao.getMaxSystemVersion();
// 按下面这种写法取得spring bean,否则update方不能启事务
version.setUpgradeDate(new Date());
SystemVersionService service = (SystemVersionService) ApplicationContextHolder.getApplicationContext().getBean(
"systemVersionService");
service.updateSystemVersion(version);
return version.getVersion();
}
解决方法二:
使该service实现 BeanSelfAware 接口类,并在该类中添加自身serivce属性, 如下写法可以使不带事务的方法变为带事务,能提交数据。具体参考类FundsAlipayServiceImpl.java中的写法。
public class SystemVersionServiceImpl implements SystemVersionService, BeanSelfAware {
private SystemVersionService selfBean;
@Cacheable(id = "getMaxSystemVersionNo")
public String getMaxSystemVersionNo() {
SystemVersion version = systemVersionDao.getMaxSystemVersion();
// 按下面这种写法取得spring bean,否则update方不能启事务
version.setUpgradeDate(new Date());
selfBean.updateSystemVersion(version);
return version.getVersion();
}
@Override
public void setSelf(Object proxyBean) {
this.selfBean = (SystemVersionService) proxyBean;
}
}
注:该写法在tddl读写分离时写操作有可能发布到从库上。
已解决,原因如下:
selfBean.updateSystemVersion(version)方法没有走AOP切面,从而导致没有启用事务,而tddl是通过事务判断走主库还是从库的,没有启用事务所以就走从库了。
selfBean方法没有走AOP切面的原因是service相互依赖调用引起的,详见下面帖子:
Spring事务处理时自我调用的解决方案及一些实现方式的风险