Welcome 微信登录

首页 / 软件开发 / JAVA / Spring事务管理高级应用难点剖析: 第3部分

Spring事务管理高级应用难点剖析: 第3部分2012-04-26 IBM 陈雄华概述

对于应用开发者来说,数据连接泄漏无疑是一个可怕的梦魇。如果存在数据连 接泄漏问题,应用程序将因数据连接资源的耗尽而崩溃,甚至还可能引起数据库的崩溃。数据 连接泄漏像黑洞一样让开发者避之唯恐不及。

Spring DAO 对所有支持的数据访问技术 框架都使用模板化技术进行了薄层的封装。只要您的程序都使用 Spring DAO 模板(如 JdbcTemplate、HibernateTemplate 等)进行数据访问,一定不会存在数据连接泄漏的问题 ― ― 这是 Spring 给予我们郑重的承诺!因此,我们无需关注数据连接(Connection)及其衍生 品(Hibernate 的 Session 等)的获取和释放的操作,模板类已经通过其内部流程替我们完成 了,且对开发者是透明的。

但是由于集成第三方产品,整合遗产代码等原因,可能需要 直接访问数据源或直接获取数据连接及其衍生品。这时,如果使用不当,就可能在无意中创造 出一个魔鬼般的连接泄漏问题。

我们知道:当 Spring 事务方法运行时,就产生一个事 务上下文,该上下文在本事务执行线程中针对同一个数据源绑定了一个唯一的数据连接(或其 衍生品),所有被该事务上下文传播的方法都共享这个数据连接。这个数据连接从数据源获取 及返回给数据源都在 Spring 掌控之中,不会发生问题。如果在需要数据连接时,能够获取这 个被 Spring 管控的数据连接,则使用者可以放心使用,无需关注连接释放的问题。

那 么,如何获取这些被 Spring 管控的数据连接呢? Spring 提供了两种方法:其一是使用数据 资源获取工具类,其二是对数据源(或其衍生品如 Hibernate SessionFactory)进行代理。在 具体介绍这些方法之前,让我们先来看一下各种引发数据连接泄漏的场景。

Spring JDBC 数据连接泄漏

如果直接从数据源获取连接,且在使用完成后不主动归还给数据源 (调用 Connection#close()),则将造成数据连接泄漏的问题。

一个具体的实例

下面,来看一个具体的实例:

清单 1.JdbcUserService.java:主体代码

package user.connleak;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.sql.Connection;

@Service("jdbcUserService")
public class JdbcUserService {
@Autowired
private JdbcTemplate jdbcTemplate;

public void logon(String userName) {
try {
// ①直接从 数据源获取连接,后续程序没有显式释放该连接
Connection conn = jdbcTemplate.getDataSource().getConnection();
String sql = "UPDATE t_user SET last_logon_time=? WHERE user_name =?";
jdbcTemplate.update(sql, System.currentTimeMillis(), userName);
Thread.sleep(1000);// ②模拟程序代码的执行时间
} catch (Exception e) {
e.printStackTrace();
}
}
}