刚刚接到一个上家公司同事的一个电话,问我为什么service方法事务不会滚了,日志打印了,调用webservice报错。
我让他把这个调用执行webservice的方法截图发给我,如下:
public Object[] send(String operationName,Object[] params,String endPoint) throws Exception { Object[] results = null; Client client = null; try { // 获取外部服务注册信息 Map<String, ExtWebserviceInfo> extMap = (Map<String, ExtWebserviceInfo>)SimpleCacheUtils.get(ExtWebService.WEBSERVICE); // 获取操作名称 if (!ToolUtil.isNullOrEmpty(extMap)) { // 获取服务方法名 String methodName = extMap.get(operationName).getServiceValue(); LOGGER.info("获取到方法标识为*"+operationName+"的操作名"+methodName); // 创建client client = new Client(new URL(endPoint)); LOGGER.info("监测到请求"+endPoint+"服务"+methodName+"操作方法的动作..."); // 执行调用 results = client.invoke(methodName, params); LOGGER.info("向"+endPoint+"服务"+methodName+"操作方法发出的请求成功..."); } } catch (Exception e) { LOGGER.info("向"+endPoint+"服务标识为"+operationName+"的操作方法发出的请求出现异常..."+e.getLocalizedMessage()); throw(Exception)new Exception().initCause(e); } finally{ if(client != null){ client.close(); } } return results; }
这个方法是一个调用执行webservice的方法,并返回执行结果给调用者,就是上面这个方法报错。我一看到这个代码,中有try catch,我想一定是这个方法中把异常给拦截了,service中捕获不到异常,导致aop拦截不到异常信息,导致事务不回滚。
但是仔细一看发现这个方法虽然捕获了异常,但是捕获后有重新抛出异常。
} catch (Exception e) { LOGGER.info("向"+endPoint+"服务标识为"+operationName+"的操作方法发出的请求出现异常..."+e.getLocalizedMessage()); throw(Exception)new Exception().initCause(e); } finally{
这不是又抛出异常了吗?应该没有问题了啊。
仔细分一下,就发现问题就出在这里,它抛出的是一个Exception,而spring在事务回滚时,是只对runtimeException或者其子类的异常才会回滚。
而且这里抛出的是一个Exception,别人调用的时候肯定提示要trycatch,如果一不小心,catch中没有重新抛出runtimeException,那就会出现事务不回滚的问题,而且此问题一般不易被发现。
总结一下:
1、spring做aop事务拦截的一般都会配置在service层;
2、service层一般情况下不能trycatch,有时候有检查行异常,那么就往上抛,如果又不想抛,那么就trycatch中在throw new RuntimeException("出错了!!!");
3、service层抛出的异常必须是runtimeException或者其子类的异常。