概述
作为一名JAVA开发者,开发已经4年了, 不知道是自己太菜还是业务太复杂,一直没有把一个东西弄明白。
那就是:异常处理
—事务回滚
—用户状态响应
这三者之间der关系。
异常处理有话say
异常处理通常有三种方式
throws Exception
throw new Exception
try catch
@1 throws Exception and throw new Exception
作用
throws Exception
是为了给某个方法声明可能抛出的异常,和程序本身是否抛出异常无关,仅是一种声明
。throws Exception
声明后,Java编译器会检测,在上层必须对此声明做出反应
,要么继续抛出要么处理异常。
@2 @Transactional(rollcallback = Exception.class)
事务回滚注意事项:
异常必须为RuntimeException或者其子类
方法必须为public
rollcallback=?
指定需要回滚的异常@Scheduled
@Async
等注解会被代理导致事务失效,因为其会被多线程管理,解决方案如下。
异步操作不需要事务管理
@Transactional @Override public void accountRegister(RequestRegisterDTO registerInfo) { // 验证以及注册信息入库 accountUserMapper.insert(xxxx); // 先让异步操作由ThreadLocal(线程本地变量)管理,事务 commit 后会去 ThreadLocal 里边获取并执行。 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { // 注册成功后异步发送邮件 emailAndShortMessageService.mailSend(xxxxxss); } }); }
异步操作需要事务管理
需要将异步操作中的业务提取到另一个
service
中,单独添加事务,达到异步调用事务管理目的,注意这和之前的事务是无法一起管理的。
举个栗子:A
方法添加了事务标记@Transactional
,A中插入一条记录之后, 调用异步方法方法B
,B
使用了@Async
来标注,B
中又调用了C、D
,C/D
分别使用@Transactional
做了标注,
则可实现B
中的事务C/D
控制的目的,但是C/D
事务是无法一起管理的,除非把C/D提取到一个方法中,并标注@Transactional
。
try catch处理异常
try catch目的
- 增强业务得健壮性,处理能处理的异常,区分日志信息,定位到某一步操作,但是太多的try catch 让代码不够简洁,难以理清业务,所以需要合理使用。
throw new Exception
是为了让程序检测到异常让事务回滚。try catch
后事务是不会回滚的,如果想要事务回滚,需要throw new Exception
。
@3 用户状态响应
建议响应
- try catch之后,需要重新返回需要的提示信息。面向用户的提示信息应该统一,可以定义constant类,统一整个业务的所有提示信息。
- 定义业务相关的错误码,对应不同的错误信息, 有时候可以自定义错误信息让不同的错误信息对应同一个错误码,错误信息用constant来管理。比如[code=404, message=”用户信息不能为空”]
@4 补充,事务执行过程中服务器挂掉了会怎样
在进行事务处理的时候会在执行SQL前记录
REDO
log和UNDO
log,redo log其实保障的是事务的持久性和一致性,而undo log则保障了事务的原子性。
正在执行中的事务如果出现异常,在程序或者数据库重启后会根据日志回滚数据,保证数据的持久性和一致性。