知识卡片
数据库连接生命周期管理:绑定到事务,而非依赖垃圾回收
内容
数据库连接是一种珍贵资源,必须在用完后立刻释放;如果建立连接开销较大,通常会用连接池来避免频繁创建/关闭(现在多数平台已自带连接池,很少需要自己实现,如果非要自建,应先确认连接池确实能带来性能提升——环境创建新连接的速度越来越快,有时反而不需要缓冲池)。管理连接要解决两个问题:一是保证任何需要连接的地方都能拿到它——把连接当参数层层传递会污染调用链(可能只是为了传给调用栈第五层下的某个方法),因此常见做法是引入一个线程范围内的注册表来存取连接(避免多线程共享同一连接);二是保证用完一定会关闭——作者明确表示不喜欢依赖垃圾回收机制来关闭连接:虽然让连接或引用它的对象在垃圾回收时顺带关闭连接与内存管理机制一致、用起来不陌生,但连接的实际关闭时间只在垃圾回收器真正回收内存时才发生,可能距离连接失去最后一个引用已经过去很久,是否构成问题要看具体环境——垃圾回收更适合当成其他机制失效时的兜底手段,而非首选方案。由于连接和事务天然紧密相关,管理连接最好的办法是把连接生命周期绑死在事务上:事务开始时打开连接,提交或回滚时关闭它,让事务自己知道在用哪个连接,这样开发者只需要关心事务、不用单独操心连接;而且事务的完成会有可见的效果,即使忘了提交也容易被发现——工作单元天然适合承担这种”同时管理事务和连接”的角色。事务之外的场景(如读取不可变数据)则可以为每个命令单独开一个新连接,交给连接池处理这种短生命周期连接。
参考来源
- 位置:《企业应用架构模式》第一部分"表述"之"第3章 映射到关系数据库"之"3.7 数据库连接"(源文件:_epub-src/OEBPS/Text/000024.html)
- 结论依据:原文说明"总的来说,我不喜欢依赖垃圾回收机制。其他的机制,甚至是显式关闭都会好一些。当然,垃圾回收机制在其他机制失败的情况下还是一种很好的后备……由于连接对于事务来说如此密不可分,因此管理它们的好方法就是把它们捆绑到事务中去……工作单元很自然地适用于管理事务和连接",直接支撑本卡结论。
- 原始内容:由于连接对于事务来说如此密不可分,因此管理它们的好方法就是把它们捆绑到事务中去。当开始一个事务的时候打开一个连接,当提交或者回滚的时候就关闭它。让事务知道它在使用什么样的连接,这样就可以完全不管连接而仅仅处理事务就可以了。