java事务异常必须手动abort且commit失败后不能静默,需在finally中确保commit或abort执行;transienttransactionerror需指数退避重试并重建事务;duplicatekeyexception和permissiondenieddataaccessexception属业务/权限问题,不触发abort但需终结事务;clientsession须用try-with-resources避免泄漏。

事务异常不处理,数据就可能半途落盘或连接池耗尽——Java原生驱动里没有自动回滚,必须手动 abort,且 commit 失败后不能静默。
commitTransaction() 抛异常后必须 abortTransaction()
commitTransaction() 可能因网络中断、写冲突(WriteConflict)、主节点切换等失败,此时会抛出 MongoException,但 session 仍处于 OPEN 状态。若没在 catch 或 finally 中调用 abortTransaction(),后续再用该 ClientSession 会直接报 IllegalStateException: Session is in transaction。
- 永远把
commitTransaction()和abortTransaction()放在同一个finally块里,确保至少执行其一 - 不要在
commitTransaction()失败后只记录日志就返回——它不等于事务已终止,必须显式abortTransaction() - 如果
abortTransaction()自身也失败(比如网络已断),说明 session 已不可用,应丢弃并新建 session,而不是重试 abort
TransientTransactionError 类型错误必须重试,但不能靠 retryWrites
TransientTransactionError 是 MongoDB 官方标记的瞬态错误(如主从切换、临时网络抖动),它出现在 commitTransaction() 或事务内操作的 errorLabels 数组中。注意:retryWrites=true 对事务完全无效,它只影响单条写命令。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 手动管理事务时,需检查异常的
errorLabels是否含"TransientTransactionError",而非依赖错误类名或消息字符串 - 重试逻辑必须重建事务:每次重试前调用
session.startTransaction(),不能复用上一轮失败的事务上下文 - 重试次数建议 ≤3 次,间隔用指数退避(如 100ms → 300ms),避免雪崩
DuplicateKeyException 和 PermissionDeniedDataAccessException 要区分业务语义
这两类异常不是事务机制问题,而是业务约束或权限配置错误,它们在事务内外都会发生,但处理方式不同:
-
DuplicateKeyException(对应 MongoDB 错误码 11000/11001):说明唯一索引冲突,属于可预期的业务校验场景,应转为用户友好的提示(如“手机号已被注册”),而非重试或回滚整个事务 -
PermissionDeniedDataAccessException(对应错误码 13):大概率是连接用户缺少readWrite角色,或对目标集合无权限,这类问题无法在代码里修复,需运维介入调整账号权限 - 两者都不该触发
abortTransaction()—— 它们不是事务执行失败,而是前置条件不满足;但要确保事务最终被显式终结(abortTransaction()或commitTransaction())
ClientSession 泄漏比事务失败更隐蔽
一个 ClientSession 实例未关闭,不会立刻报错,但会持续占用连接池资源。当大量请求创建 session 却未 close,连接池会逐渐耗尽,最终所有数据库操作卡住或超时。
- 必须用 try-with-resources 包裹
client.startSession(),或显式调用session.close() - Spring 的
@Transactional不接管原生ClientSession,别混用——它和 Spring 的MongoTransactionManager是两套生命周期 - 日志中留意
InvalidSessionException:这往往意味着你复用了已 abort 或已 close 的 session
事务异常真正的复杂点不在捕获,而在判断:这个错误是该重试、该提示用户、该告警运维,还是该立即终止?而所有判断都依赖你是否真的检查了 errorLabels、是否严格复用同一个 ClientSession、以及是否在每个退出路径上都终结了事务状态。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










