您的位置:首页 > 编程语言 > Java开发

实际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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring spring mvc 异常