实际springMVC项目中自定义异常、spring事务与异常的简单应用
2016-09-21 14:12
555 查看
一、异常相关知识:
非运行时异常(Checked Exception)Java中凡是继承自Exception但不是继承自RuntimeException的类都是非运行时异常。
运行时异常(Runtime Exception/Unchecked Exception)
RuntimeException类直接继承自Exception类,称为运行时异常。Java中所有的运行时异常都直接或间接的继承自RuntimeException。
3、Java中所有的异常类都直接或间接的继承自Exception。
4、spring事务回滚机制只处理运行时异常,发生非运行时异常则不会回滚操作。
二、自定义异常的大体思路
1、通过上面异常相关知识介绍,在实际的springmvc项目中自定义异常采用继承RuntimeException类的方式;2、为了防止注解了spring事务的service方法中发生非运行其异常,导致的事务不回滚操作,service层触发事务相关代码主动用try{}catch(){}包裹,最后的catch捕获Exception异常(即包含了运行期和非运行期异常),
catch内部抛出自定义的运行期异常,以达到把非运行其异常转换为运行期异常的效果,保证所有异常spring事务都执行回滚操作。
三、自定义异常实例
自定义基类异常:/** * 所有秒杀相关异常(运行期异常) * spring事务,只接收运行期异常,执行回滚操作 */ public class SeckillException extends RuntimeException{ private static final long serialVersionUID = 1L; //重载构造函数 public SeckillException(String message, Throwable cause) { super(message, cause); } //重载构造函数 public SeckillException(String message) { super(message); } }
自定义两个子类异常:
/** * 秒杀关闭异常:可能未开启,可能已结束(时间到期,库存为0),可能执行失败等 * 秒杀异常的子类型异常 */ public class SeckillClosedException extends SeckillException{ private static final long serialVersionUID = 1L; //重载构造函数 public SeckillClosedException(String message, Throwable cause) { super(message, cause); } //重载构造函数 public SeckillClosedException(String message) { super(message); } }
/** * 重复秒杀异常,秒杀异常的子类型异常 */ public class RepeatSeckillException extends SeckillException{ private static final long serialVersionUID = 1L; //重载构造函数 public RepeatSeckillException(String message){ super(message); } //重载构造函数 public RepeatSeckillException(String message,Throwable cause){ super(message, cause); } }
service层事务方法:
@Transactional @Override public SeckillExecution executeSeckill(。。。) throws SeckillException, SeckillClosedException,RepeatSeckillException { //将所有操作用try{}catch(){}包裹,然后在catch中抛出运行期异常,以便发生异常时spring事务回滚操作 try{ //insert语句并没有触发事务操作,但是inset要保证与update事务的一致性 int insertCount = successkilledDao.insertSuccessKilled(seckillId, userPhone); //重复秒杀 if(insertCount <= 0){ throw new RepeatSeckillException(SeckillStateEnum.REPEAT_KILL.getStateInfo()); }else{ //减库存 Date nowTime = new Date(); //开启事务,获取updateCount值,提交并关闭事务;如果抛出异常则回滚事务 int updateCount = seckillDao.reduceNumber(seckillId, nowTime); //没有更新数据,秒杀结束 if(updateCount <= 0){ throw new SeckillClosedException(SeckillStateEnum.END.getStateInfo()); }else{ //秒杀成功,获取当前购买明细实体 SuccessKilled successKilled = successkilledDao.querySuccessKilledWithSeckill(seckillId, userPhone); return new SeckillExecution(seckillId,SeckillStateEnum.SUCCESS,successKilled); } } //将try中抛出的已知异常用已知异常捕获,然后再次抛出 //为的是避免被最后的用于处理未知异常的Exception e捕获,让调用者获取最为准确的信息 }catch(SeckillClosedException se){ logger.error(se.getMessage()); throw se; }catch(RepeatSeckillException re){ logger.error(re.getMessage()); throw re; //最后捕获所有未知异常(相对于上面两个已知异常),然后再主动抛出自定义运行期异常 }catch(Exception e){ logger.error(e.getMessage(),e); //将检查(编译期)异常转换为运行期异常,spring事务回滚只负责运行期异常 throw new SeckillException(SeckillStateEnum.INSERT_ERROR.getStateInfo()+" : "+e.getMessage()); } }
上述方式的弊端是,如果业务线比较多,自定义的异常子类也会比较多,完全可以定义为一个通用的UncheckedException异常,如下:
/** * @Description:通用的UncheckedException异常,继承RuntimeException,为运行期异常 */ public class UncheckedException extends RuntimeException { private static final long serialVersionUID = 1L; /** 错误Key,用于唯一标识错误类型 */ private String errorCode = null; /** 错误信息 */ private String errorMessage; /** 传递给变量的错误值 */ private Object[] errorParam = null; /** * 构造函数 * @param errorCode 异常编码 */ public UncheckedException(String errorCode) { this.errorCode = errorCode; } /** * 构造函数 * @param errorCode 异常编码 * @param errorParam Object[] 异常信息用到的参数 */ public UncheckedException(String errorCode, Object[] errorParam) { this.errorCode = errorCode; this.errorParam = errorParam; } /** * 重载构造函数 * @param errorCode 异常编码 * @param errorParam 异常信息用到的参数 * @param t 异常实例 */ public UncheckedException(String errorCode, Object[] errorParam, Throwable t) { super(t); this.errorCode = errorCode; this.errorParam = errorParam; } /** * 重载构造函数 * @param message 异常信息 * @param t 异常实例 */ public UncheckedException(String message, Throwable t) { super(message, t); setErrorMessage(message); } /** * 异常编码 * @return String */ public String getErrorCode() { return this.errorCode; } /** * 异常信息用到的参数 * @return Object[] */ public Object[] getErrorParam() { return this.errorParam; } /** * 错误信息 * * @return */ public String getErrorMessage() { return errorMessage; } /** * 错误信息 * * @param errorMessage */ public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } /** * 覆盖方法:getMessage * @return String */ @Override public String getMessage() { if (errorMessage != null) { return errorMessage; } //异常信息以资源文件的形式保存,并且支持国际化,此处通过errorCode去读取国际化异常信息 if (errorCode != null && !errorCode.trim().equals("")) { setErrorMessage(AppLang.getLU().getMessage(errorCode, errorParam,Locale.SIMPLIFIED_CHINESE)); } return getErrorMessage(); } }
相关文章推荐
- 在springMVC+mybatis+Ajax+JSON+jQuery easyui的项目中,自定义全局异常处理器
- 抛出自定义异常,spring AOP事务不回滚的解决方案
- springBoot事件监听 在项目实际业务中的异步应用
- IDEA进行springmvc项目开发三(springboot搭建简单springmvc)
- Jwt在Java项目中的简单实际应用
- springMvc、Spring项目异常处理和Log4j的配置(转)
- 框架 day89 涛涛商城项目(补)-activeMQ应用,及springMVC全局异常处理
- 解决Spring的声明式事务中的自定义异常不回滚问题
- Java自定义异常在项目中的应用
- 项目应用:自定义异常处理
- spring拦截自定义异常并回滚当前事务
- spring加mybatis(Maven构建项目)简单篇---旨在探究spring配置方法和spring项目出现的异常分析
- 项目总结--maven+springsecurity+solr+springmvc+hibernate 延迟加载处理+hibernate sql对象处理(sql执行插入)+spring注解方式+邮件 + JNDI+项目框架写法+jasperreprot的简单应用
- springmvc 项目完整示例01 需求与数据库表设计 简单的springmvc应用实例 web项目
- .NET自定义异常的一个简单应用
- MyBatis和SpringMVC集成事务在Junit测试下有效但是在实际项目无效的问题
- 线程在实际项目中简单的应用
- springboot实际项目:日志打印、表单验证、异常处理
- SpringMVC案例3----spring3.0项目拦截器、ajax、文件上传应用
- spring、springMVC简单应用FutureTask(线程池)