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