service层事务与try/catch的关系

本文详细解析了Spring框架中的事务回滚机制,包括不同类型的异常如何影响事务的状态,特别是unchecked异常与checked异常的区别,以及如何正确处理这些异常以确保事务能够按照预期回滚。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先了解一下异常的组成:

1、RuntimeException()  例如:数组越界异常、空指针异常、(我们在编写之后不会提示让 try catch的异常、代码编写错误导致,可避免)

2、非RuntimeException() 例如: IO异常、(会提示try catch的异常,不是代码编写错误导致的,只能抛出)

3、unchecked异常:RuntimeException + Error

4、checked异常:非RuntimeException()

详细文章:http://blog.youkuaiyun.com/qq_14982047/article/details/50989761

spring通过异常进行事务回滚的机制:

1、spring 的默认事务机制,当出现unchecked异常时候回滚,checked异常的时候不会回滚;

2、我们有时为了打印日志,会在service层抓住Exception并打印日志,这时我们的所有异常都会被认为成checked异常。

3、为了事务的正常生效:当有try catch后捕获了异常,事务不会回滚,如果不得不在service层写try catch 需要catch后 throw new RuntimeException 让事务回滚;

例子:

try {    
    } catch (Exception e) {
		e.printStackTrace();
		logger.error("发生异常");
		throw new RuntimeException();
	}

如何保证在有返回值的方法中进行异常的捕获?

方法1:

因为要保证当前方法具有返回值,在前端界面展示操作状态。所以我们service层在添加了try catch日志打印后,抛出的runtime类异常需要在controller层进行捕获,捕获之后,在catch中编写操作失败后返回值的信息。

方法2:

不依赖于spring的异常捕获机制进行事务回滚,通过手动的session.rollback进行异常捕获后回滚事务也可。



在使用 `try/catch` 时遇到问题,通常异常捕获的范围、类型以及语言特性有关。以下是一些常见问题及其解决方案: ### 1. 捕获系统级异常(如段错误、除零等) 在 C++ 中,标准的 `try/catch` 只能捕获通过 `throw` 抛出的异常,并不能处理系统级异常,例如访问非法内存地址或除以零等操作。为了解决这类问题,可以使用 Windows 特有的 **结构化异常处理**(SEH),即 `__try/__except` 块来捕获硬件异常[^1]。 ```cpp #include <windows.h> __try { // 可能引发异常的代码 int a = 5 / 0; } __except (EXCEPTION_EXECUTE_HANDLER) { printf("捕获到除零异常\n"); } ``` 对于 Qt 程序员,虽然 `QT_TRY/QT_CATCH` 是兼容 SEH 的封装,但在某些情况下仍无法替代原生 SEH 处理机制。 ### 2. PHP 中无法捕获致命错误 PHP 的 `try/catch` 在早期版本中仅能捕获 `Exception` 类型的异常,而无法捕获致命错误(如 `E_ERROR`)。从 PHP 7 开始,很多致命错误被转换为 `Error` 实例,它们实现了 `Throwable` 接口,因此可以通过如下方式统一捕获: ```php try { // 可能抛出异常或错误的代码 } catch (\Throwable $t) { echo "捕获到异常或错误:" . $t->getMessage(); } ``` 此外,若设置了自定义错误处理器(如 `set_error_handler()`),但未将其转换为异常,则这些错误也不会进入 `try/catch` 流程中。 ### 3. Java 中局部变量作用域问题 在 Java 中,如果在 `try` 块内部声明变量,外部将无法访问该变量。为避免此类编译错误,应在 `try/catch` 外部声明变量,并在块内进行赋值: ```java public void test() { String result = null; try { result = JsonUtils.object2Json(map); } catch (IOException e) { e.printStackTrace(); } System.out.println(result); // 正常引用 } ``` 此做法确保了变量的作用域足够宽泛,可被后续代码访问[^3]。 ### 4. JavaScript Promise 异常捕获失败 在异步编程中,直接对 `Promise.reject()` 使用 `try/catch` 是无效的,因为 `Promise` 错误是异步触发的。应使用 `.catch()` 方法或者 `await` 配合 `try/catch` 来正确捕获异常: ```javascript async function f2() { try { await new Promise((resolve, reject) => { reject('出错了'); }); } catch (e) { console.log(e); // 成功捕获 } } f2(); ``` 如果不使用 `await`,则需通过链式调用 `.catch()` 来处理错误: ```javascript function f2() { Promise.reject('出错了') .catch(e => console.log(e)); // 捕获并处理错误 } ``` ### 5. Spring Boot Service 数据库异常捕获失效 当将数据库操作逻辑从 Controller 移动至 Service 后,可能出现异常捕获失效的问题。这通常是由于事务管理配置不当导致的。Spring 默认不会将异常传播到上,除非明确声明事务回滚策略。 解决方法包括: - 使用 `@Transactional(rollbackFor = Exception.class)` 注解,强制事务在所有异常下回滚。 - 明确抛出受检异常或运行时异常,确保异常能够穿透事务代理。 - 若需要自定义异常处理逻辑,建议结合 `@ControllerAdvice` 或 `@ExceptionHandler` 进行全局异常管理。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值