Java中不应直接传递Connection对象,因其携带事务状态、隔离级别等上下文,必须与业务作用域严格对齐;应依赖DataSource按需获取,并在方法内用try-with-resources自动释放,禁止跨层传递、静态持有或跨线程复用。

Java 中不应直接传递 Connection 对象,这是破坏事务边界的常见根源。Connection 是一次事务的载体,其生命周期必须与业务逻辑作用域严格对齐——不是“传出去”,而是“在需要的地方获取、在作用域结束时释放”。
事务边界必须由连接获取点定义
Connection 的创建(如 dataSource.getConnection())即隐式开启事务起点(尤其在 autoCommit=false 时)。一旦你把 Connection 从 DAO 层传给 Service 层、再传给另一个工具类,就等于把事务控制权交给了不可控的调用链,极易导致:
- 连接被意外复用到不同事务中(例如两次转账共用一个 Connection,但未隔离)
- 事务未提交/回滚就脱离作用域,连接归还池后状态残留
- 异步或线程切换后 Connection 被跨线程使用(JDBC 连接非线程安全)
推荐做法:依赖 DataSource,而非 Connection
各层应只持有 DataSource 或事务管理器(如 Spring 的 TransactionTemplate),由统一入口按需获取 Connection:
- DAO 层通过
DataSource.getConnection()获取连接,并在方法内完成所有操作和关闭(配合 try-with-resources) - Spring 环境下,用
@Transactional注解声明事务边界,让框架自动绑定 Connection 到当前线程(ThreadLocal) - 若需手动控制(如批处理),在同一个方法内获取、使用、关闭 Connection,不传出该方法作用域
避免缓存或静态持有 Connection
Connection 不是可重用的“工具对象”,它携带事务状态、隔离级别、保存点等上下文信息:
- 禁止将 Connection 存入 static 字段、单例 Bean 或 ThreadLocal(除非明确受事务管理器控制)
- 禁止在工具类中提供“全局 getConnection()”方法并长期持有返回值
- 若使用异步(如
CompletableFuture),务必确认 Connection 在thenApply或whenComplete中已释放,不跨 CompletableFuture 链传递
多数据源或嵌套场景的处理原则
当涉及多个数据库或子事务时,更不能靠手动传 Connection 解决:
- 使用 JTA 或 Spring 的
ChainedTransactionManager协调多资源 - 若用编程式事务,每个数据源独立获取自己的 Connection,在各自 try-with-resources 块中管理
- 切勿用一个 Connection 操作两个不同数据库(MySQL + PostgreSQL),这违反 JDBC 规范且事务无法保证
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











