Spring的事务管理难点剖析(7):数据连接泄漏(四)

2014-11-24 08:51:31 · 作者: · 浏览: 11
d doReleaseConnection(Connection con, DataSource dataSource):释放连接,放回到连接池中;
static void releaseConnection(Connection con, DataSource dataSource):和doRelease Connection方法的功能一样,实际上,它内部就是调用doReleaseConnection方法获取连接的。

来看一下DataSourceUtils从数据源获取连接的关键代码:

01 public abstract class DataSourceUtils {

02 …

03 public static Connection doGetConnection(DataSource dataSource) throws SQLException {

04 Assert.notNull(dataSource, "No DataSource specified");

05

06 //①首先尝试从事务同步管理器中获取数据连接

07 ConnectionHolder conHolder =

08 (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

09 if (conHolder != null && (conHolder.hasConnection() ||

10 conHolder.isSynchronizedWithTransaction())) {

11 conHolder.requested();

12 if (!conHolder.hasConnection()) {

13 logger.debug("Fetching resumed JDBC Connection from DataSource");

14 conHolder.setConnection(dataSource.getConnection());

15 }

16 return conHolder.getConnection();

17 }

18

19 //②如果获取不到连接,则直接从数据源中获取连接

20 Connection con = dataSource.getConnection();

21

22 //③如果拥有事务上下文,则将连接绑定到事务上下文中

23 if (TransactionSynchronizationManager.isSynchronizationActive()) {

24 ConnectionHolder holderToUse = conHolder;

25 if (holderToUse == null) {

26 holderToUse = new ConnectionHolder(con);

27 }

28 else {holderToUse.setConnection(con);}

29 holderToUse.requested();

30 TransactionSynchronizationManager.registerSynchronization(

31 new ConnectionSynchronization(holderToUse, dataSource));

32 holderToUse.setSynchronizedWithTransaction(true);

33 if (holderToUse != conHolder) {

34 TransactionSynchronizationManager.bindResource(

35 dataSource, holderToUse);

36 }

37 }

38 return con;

39 }

40 …

41 }

它首先查看当前是否存在事务管理上下文,并尝试从事务管理上下文获取连接,如果获取失败,直接从数据源中获取连接。在获取连接后,如果当前拥有事务上下文,则将连接绑定到事务上下文中。
我们在JdbcUserService中,使用DataSourceUtils.getConnection()替换直接从数据源中获取连接的代码:

01 package com.baobaotao.connleak;

02 …

03 @Service("jdbcUserService")

04 public class JdbcUserService {

05 @Autowired

06 private JdbcTemplate jdbcTemplate;

07

08 @Transactional

09 public void logon(String userName) {

10 try {

11 //①使用DataSourceUtils获取数据连接

12 Connection conn =

13 DataSourceUtils.getConnection(jdbcTemplate.getDataSource());

14 //Connection conn = jdbcTemplate.getDataSource().getConnection();

15

16 String sql = "UPDATE t_user SET last_logon_time= WHERE user_name = ";

17 jdbcTemplate.update(sql, System.currentTimeMillis(), userName);

18 Thread.sleep(1000);

19 } catch (Exception e) {

20 e.printStackTrace();

21 }

22 }

23 }

重新运行代码,得到如下的执行结果:


引用
连接数[active:idle]-[0:0]
连接数[active:idle]-[1