1 16 17 package org.springframework.jdbc.datasource; 18 19 import java.sql.Connection ; 20 import java.sql.SQLException ; 21 import java.sql.Statement ; 22 23 import javax.sql.DataSource ; 24 25 import org.apache.commons.logging.Log; 26 import org.apache.commons.logging.LogFactory; 27 28 import org.springframework.jdbc.CannotGetJdbcConnectionException; 29 import org.springframework.transaction.TransactionDefinition; 30 import org.springframework.transaction.support.TransactionSynchronizationAdapter; 31 import org.springframework.transaction.support.TransactionSynchronizationManager; 32 import org.springframework.util.Assert; 33 34 52 public abstract class DataSourceUtils { 53 54 58 public static final int CONNECTION_SYNCHRONIZATION_ORDER = 1000; 59 60 private static final Log logger = LogFactory.getLog(DataSourceUtils.class); 61 62 63 77 public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { 78 try { 79 return doGetConnection(dataSource); 80 } 81 catch (SQLException ex) { 82 throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex); 83 } 84 } 85 86 98 public static Connection doGetConnection(DataSource dataSource) throws SQLException { 99 Assert.notNull(dataSource, "No DataSource specified"); 100 101 ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); 102 if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) { 103 conHolder.requested(); 104 if (!conHolder.hasConnection()) { 105 logger.debug("Fetching resumed JDBC Connection from DataSource"); 106 conHolder.setConnection(dataSource.getConnection()); 107 } 108 return conHolder.getConnection(); 109 } 110 112 logger.debug("Fetching JDBC Connection from DataSource"); 113 Connection con = dataSource.getConnection(); 114 115 if (TransactionSynchronizationManager.isSynchronizationActive()) { 116 logger.debug("Registering transaction synchronization for JDBC Connection"); 117 ConnectionHolder holderToUse = conHolder; 120 if (holderToUse == null) { 121 holderToUse = new ConnectionHolder(con); 122 } 123 else { 124 holderToUse.setConnection(con); 125 } 126 holderToUse.requested(); 127 TransactionSynchronizationManager.registerSynchronization( 128 new ConnectionSynchronization(holderToUse, dataSource)); 129 holderToUse.setSynchronizedWithTransaction(true); 130 if (holderToUse != conHolder) { 131 TransactionSynchronizationManager.bindResource(dataSource, holderToUse); 132 } 133 } 134 135 return con; 136 } 137 138 146 public static Integer prepareConnectionForTransaction(Connection con, TransactionDefinition definition) 147 throws SQLException { 148 149 Assert.notNull(con, "No Connection specified"); 150 151 if (definition != null && definition.isReadOnly()) { 153 try { 154 if (logger.isDebugEnabled()) { 155 logger.debug("Setting JDBC Connection [" + con + "] read-only"); 156 } 157 con.setReadOnly(true); 158 } 159 catch (Throwable ex) { 160 logger.debug("Could not set JDBC Connection read-only", ex); 163 } 164 } 165 166 Integer previousIsolationLevel = null; 168 if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { 169 if (logger.isDebugEnabled()) { 170 logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " + 171 definition.getIsolationLevel()); 172 } 173 previousIsolationLevel = new Integer (con.getTransactionIsolation()); 174 con.setTransactionIsolation(definition.getIsolationLevel()); 175 } 176 177 return previousIsolationLevel; 178 } 179 180 187 public static void resetConnectionAfterTransaction(Connection con, Integer previousIsolationLevel) { 188 Assert.notNull(con, "No Connection specified"); 189 try { 190 if (previousIsolationLevel != null) { 192 if (logger.isDebugEnabled()) { 193 logger.debug("Resetting isolation level of JDBC Connection [" + 194 con + "] to " + previousIsolationLevel); 195 } 196 con.setTransactionIsolation(previousIsolationLevel.intValue()); 197 } 198 199 if (con.isReadOnly()) { 201 if (logger.isDebugEnabled()) { 202 logger.debug("Resetting read-only flag of JDBC Connection [" + con + "]"); 203 } 204 con.setReadOnly(false); 205 } 206 } 207 catch (Throwable ex) { 208 logger.debug("Could not reset JDBC Connection after transaction", ex); 209 } 210 } 211 212 220 public static boolean isConnectionTransactional(Connection con, DataSource dataSource) { 221 if (dataSource == null) { 222 return false; 223 } 224 ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); 225 return (conHolder != null && connectionEquals(conHolder, con)); 226 } 227 228 236 public static void applyTransactionTimeout(Statement stmt, DataSource dataSource) throws SQLException { 237 applyTimeout(stmt, dataSource, 0); 238 } 239 240 249 public static void applyTimeout(Statement stmt, DataSource dataSource, int timeout) throws SQLException { 250 Assert.notNull(stmt, "No Statement specified"); 251 Assert.notNull(dataSource, "No DataSource specified"); 252 ConnectionHolder holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); 253 if (holder != null && holder.hasTimeout()) { 254 stmt.setQueryTimeout(holder.getTimeToLiveInSeconds()); 256 } 257 else if (timeout > 0) { 258 stmt.setQueryTimeout(timeout); 260 } 261 } 262 263 272 public static void releaseConnection(Connection con, DataSource dataSource) { 273 try { 274 doReleaseConnection(con, dataSource); 275 } 276 catch (SQLException ex) { 277 logger.debug("Could not close JDBC Connection", ex); 278 } 279 catch (Throwable ex) { 280 logger.debug("Unexpected exception on closing JDBC Connection", ex); 281 } 282 } 283 284 295 public static void doReleaseConnection(Connection con, DataSource dataSource) throws SQLException { 296 if (con == null) { 297 return; 298 } 299 300 if (dataSource != null) { 301 ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource); 302 if (conHolder != null && connectionEquals(conHolder, con)) { 303 conHolder.released(); 305 return; 306 } 307 } 308 309 if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) { 312 logger.debug("Returning JDBC Connection to DataSource"); 313 con.close(); 314 } 315 } 316 317 327 private static boolean connectionEquals(ConnectionHolder conHolder, Connection passedInCon) { 328 if (!conHolder.hasConnection()) { 329 return false; 330 } 331 Connection heldCon = conHolder.getConnection(); 332 return (heldCon == passedInCon || heldCon.equals(passedInCon) || 335 getTargetConnection(heldCon).equals(passedInCon)); 336 } 337 338 346 public static Connection getTargetConnection(Connection con) { 347 Connection conToUse = con; 348 while (conToUse instanceof ConnectionProxy) { 349 conToUse = ((ConnectionProxy) conToUse).getTargetConnection(); 350 } 351 return conToUse; 352 } 353 354 362 private static int getConnectionSynchronizationOrder(DataSource dataSource) { 363 int order = CONNECTION_SYNCHRONIZATION_ORDER; 364 DataSource currDs = dataSource; 365 while (currDs instanceof DelegatingDataSource) { 366 order--; 367 currDs = ((DelegatingDataSource) currDs).getTargetDataSource(); 368 } 369 return order; 370 } 371 372 373 378 private static class ConnectionSynchronization extends TransactionSynchronizationAdapter { 379 380 private final ConnectionHolder connectionHolder; 381 382 private final DataSource dataSource; 383 384 private int order; 385 386 private boolean holderActive = true; 387 388 public ConnectionSynchronization(ConnectionHolder connectionHolder, DataSource dataSource) { 389 this.connectionHolder = connectionHolder; 390 this.dataSource = dataSource; 391 this.order = getConnectionSynchronizationOrder(dataSource); 392 } 393 394 public int getOrder() { 395 return this.order; 396 } 397 398 public void suspend() { 399 if (this.holderActive) { 400 TransactionSynchronizationManager.unbindResource(this.dataSource); 401 if (this.connectionHolder.hasConnection() && !this.connectionHolder.isOpen()) { 402 releaseConnection(this.connectionHolder.getConnection(), this.dataSource); 407 this.connectionHolder.setConnection(null); 408 } 409 } 410 } 411 412 public void resume() { 413 if (this.holderActive) { 414 TransactionSynchronizationManager.bindResource(this.dataSource, this.connectionHolder); 415 } 416 } 417 418 public void beforeCompletion() { 419 if (!this.connectionHolder.isOpen()) { 425 TransactionSynchronizationManager.unbindResource(this.dataSource); 426 this.holderActive = false; 427 if (this.connectionHolder.hasConnection()) { 428 releaseConnection(this.connectionHolder.getConnection(), this.dataSource); 429 } 430 } 431 } 432 433 public void afterCompletion(int status) { 434 if (this.holderActive) { 438 if (TransactionSynchronizationManager.hasResource(this.dataSource)) { 441 TransactionSynchronizationManager.unbindResource(this.dataSource); 442 } 443 this.holderActive = false; 444 if (this.connectionHolder.hasConnection()) { 445 releaseConnection(this.connectionHolder.getConnection(), this.dataSource); 446 this.connectionHolder.setConnection(null); 448 } 449 this.connectionHolder.reset(); 450 } 451 } 452 } 453 454 } 455 | Popular Tags |