简述织梦网站上传及安,零食网站建设的必要性,做网站的都改行做什么了,做网站还有用通过AOP实现事务处理可以理解为#xff0c;适用try...catch... 来包裹标记了Transactional注解的方法#xff0c;当方法出现了异常并且满足一定条件的时候#xff0c;在catch里面我们可以设置事务回滚#xff0c;没有异常则直接提交事务。
这里的“一定条件”#xff0c;… 通过AOP实现事务处理可以理解为适用try...catch... 来包裹标记了Transactional注解的方法当方法出现了异常并且满足一定条件的时候在catch里面我们可以设置事务回滚没有异常则直接提交事务。
这里的“一定条件”主要包括两点 第一只有异常传播出了标记了Transactional注解的方法事务才能回滚。在Spring的TransactionAspectSupport里有个invokeWithinTransaction方法里面就是处理事务的逻辑。可以看到有捕获到异常才能进行后续事务处理
try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal invocation.proceedWithInvocation();
} catch (Throwable ex) {// target invocation exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;
} finally {cleanupTransactionInfo(txInfo);
} 第二默认情况下出现RuntimeException非受检异常或Error的时候Spring才会回滚事务。
打开Spring的DefaultTransactionAttribute类能看到如下代码块可以发现相关证据通过注释也能看到Spring这么做的原因大概的意思是受检异常一般是业务异常或者说是类似另一种方法的返回值出现这样的异常可能有业务还未完成所以不会主动回滚二Error或RuntimeException代表了非预期的结果应该回滚
/*** The default behavior is as with EJB: rollback on unchecked exception* ({link RuntimeException}), assuming an unexpected outcome outside of any* business rules. Additionally, we also attempt to rollback on {link Error} which* is clearly an unexpected outcome as well. By contrast, a checked exception is* considered a business exception and therefore a regular expected outcome of the* transactional business method, i.e. a kind of alternative return value which* still allows for regular completion of resource operations.* pThis is largely consistent with TransactionTemplates default behavior,* except that TransactionTemplate also rolls back on undeclared checked exceptions* (a corner case). For declarative transactions, we expect checked exceptions to be* intentionally declared as business exceptions, leading to a commit by default.* see org.springframework.transaction.support.TransactionTemplate#execute*/
Override
public boolean rollbackOn(Throwable ex) {return (ex instanceof RuntimeException || ex instanceof Error);
} 反例
在 createUserWrong1 方法中会抛出一个 RuntimeException但由于方法内 catch 了所有异常异常无法从方法传播出去事务自然无法回滚。
在 createUserWrong2 方法中注册用户的同时会有一次 otherTask 文件读取操作如果文件读取失败我们希望用户注册的数据库操作回滚。虽然这里没有捕获异常但因为 otherTask 方法抛出的是受检异常createUserWrong2 传播出去的也是受检异常事务同样不会回滚。
Service
Slf4j
public class UserService {Autowiredprivate UserRepository userRepository;//异常无法传播出方法导致事务无法回滚Transactionalpublic void createUserWrong1(String name) {try {userRepository.save(new UserEntity(name));throw new RuntimeException(error);} catch (Exception ex) {log.error(create user failed, ex);}}//即使出了受检异常也无法让事务回滚Transactionalpublic void createUserWrong2(String name) throws IOException {userRepository.save(new UserEntity(name));otherTask();}//因为文件不存在一定会抛出一个IOExceptionprivate void otherTask() throws IOException {Files.readAllLines(Paths.get(file-that-not-exist));}}
Controller 中的实现仅仅是调用 UserService 的 createUserWrong1 和 createUserWrong2 方法这里就贴出实现了。这 2 个方法的实现和调用虽然完全避开了事务不生效的坑但因为异常处理不当导致程序没有如我们期望的文件操作出现异常时回滚事务。
现在我们来看下修复方式以及如何通过日志来验证是否修复成功。针对这 2 种情况对应的修复方法如下。
第一如果你希望自己捕获异常进行处理的话也没关系可以手动设置让当前事务处于回滚状态
Transactional
public void createUserRight1(String name) {try {userRepository.save(new UserEntity(name));throw new RuntimeException(error);} catch (Exception ex) {log.error(create user failed, ex);TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}
运行后可以在日志中看到 Rolling back 字样确认事务回滚了。同时我们还注意到“Transactional code has requested rollback”的提示表明手动请求回滚
[22:14:49.352] [http-nio-45678-exec-4] [DEBUG] [o.s.orm.jpa.JpaTransactionManager :698 ] - Transactional code has requested rollback
[22:14:49.353] [http-nio-45678-exec-4] [DEBUG] [o.s.orm.jpa.JpaTransactionManager :834 ] - Initiating transaction rollback
[22:14:49.353] [http-nio-45678-exec-4] [DEBUG] [o.s.orm.jpa.JpaTransactionManager :555 ] - Rolling back JPA transaction on EntityManager [SessionImpl(1906719643open)]
第二在注解中声明期望遇到所有的 Exception 都回滚事务来突破默认不回滚受检异常的限制
Transactional(rollbackFor Exception.class)
public void createUserRight2(String name) throws IOException {userRepository.save(new UserEntity(name));otherTask();
}
运行后同样可以在日志中看到回滚的提示
[22:10:47.980] [http-nio-45678-exec-4] [DEBUG] [o.s.orm.jpa.JpaTransactionManager :834 ] - Initiating transaction rollback
[22:10:47.981] [http-nio-45678-exec-4] [DEBUG] [o.s.orm.jpa.JpaTransactionManager :555 ] - Rolling back JPA transaction on EntityManager [SessionImpl(1419329213open)]