今天,面试的时候,突然被问到了一个点,结果,这个自己踩的坑,自己都忘记了。
前年,接手了一个项目,一直会有并发的情况,导致插入重复数据的情况。所以在项目中使用了事务 + 数据库锁,来处理并发。
伪代码如下:
@Transactional
public <T> T lock(Staff staff, Trade trade, ILockCallback<T> lockCallback) {
T result;
long start = System.currentTimeMillis();
try {
//先插入数据库锁
dao.batchInsert(staff, trade);
//对订单的业务操作
result = lockCallback.callback();
//提交,释放锁
} catch (Exception e) {
//回滚,释放锁
logger.error("处理出错, 记录相关的出错日志");
throw new LockException(e.getMessage());
} finally {
if (logger.isDebugEnabled()){
logger.debug("执行结束, 记录相关耗时"");
}
}
return result;
}
如果,处理业务逻辑出错了,怎么办,当然是事务回滚了。 然后大佬问了句,出现了这个异常,但是不能触发回滚怎么办,我的第一反应,放在了后面定时清理数据库中相关锁记录的数据上。
事后想想,才get到点,“出现了异常,不能触发回滚”,这个就是当时我踩到的坑,Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。所以catch住粗粒度异常(项目汇总不要catch粗异常),抛异常这里要自己封装下异常,这个异常是要继承runtimeexception, error类和runtimeexception及其子类是unchecked exception,至于什么是unchecked exception,什么是checked exception 可以看我之前的总结。
嘛耶,搞这么久,居然这么坑点,自己忘记了。。。。
基于Spring的AOP即声明式事务管理默认是针对unchecked exception回滚这个原理,可以有很多套路的来处理业务的。
这也是,正常我们写一个项目中,最最基本的简单处理方式了。