1 package org.hibernate.jdbc; 3 4 import java.sql.CallableStatement ; 5 import java.sql.Connection ; 6 import java.sql.PreparedStatement ; 7 import java.sql.ResultSet ; 8 import java.sql.SQLException ; 9 import java.util.HashSet ; 10 import java.util.Iterator ; 11 12 import org.apache.commons.logging.Log; 13 import org.apache.commons.logging.LogFactory; 14 import org.hibernate.AssertionFailure; 15 import org.hibernate.HibernateException; 16 import org.hibernate.ScrollMode; 17 import org.hibernate.dialect.Dialect; 18 import org.hibernate.engine.SessionFactoryImplementor; 19 import org.hibernate.exception.JDBCExceptionHelper; 20 import org.hibernate.util.GetGeneratedKeysHelper; 21 import org.hibernate.util.JDBCExceptionReporter; 22 23 28 public abstract class AbstractBatcher implements Batcher { 29 30 private static int globalOpenPreparedStatementCount; 31 private static int globalOpenResultSetCount; 32 33 private int openPreparedStatementCount; 34 private int openResultSetCount; 35 36 protected static final Log log = LogFactory.getLog(AbstractBatcher.class); 37 protected static final Log SQL_LOG = LogFactory.getLog("org.hibernate.SQL"); 38 39 private final ConnectionManager connectionManager; 40 private final SessionFactoryImplementor factory; 41 42 private PreparedStatement batchUpdate; 43 private String batchUpdateSQL; 44 45 private HashSet statementsToClose = new HashSet (); 46 private HashSet resultSetsToClose = new HashSet (); 47 private PreparedStatement lastQuery; 48 49 private boolean releasing = false; 50 51 public AbstractBatcher(ConnectionManager connectionManager) { 52 this.connectionManager = connectionManager; 53 this.factory = connectionManager.getFactory(); 54 } 55 56 protected PreparedStatement getStatement() { 57 return batchUpdate; 58 } 59 60 public CallableStatement prepareCallableStatement(String sql) 61 throws SQLException , HibernateException { 62 executeBatch(); 63 logOpenPreparedStatement(); 64 return getCallableStatement( connectionManager.getConnection(), sql, false); 65 } 66 67 public PreparedStatement prepareStatement(String sql) 68 throws SQLException , HibernateException { 69 return prepareStatement(sql, false); 70 } 71 72 public PreparedStatement prepareStatement(String sql, boolean getGeneratedKeys) 73 throws SQLException , HibernateException { 74 executeBatch(); 75 logOpenPreparedStatement(); 76 return getPreparedStatement( connectionManager.getConnection(), sql, false, getGeneratedKeys, null, false ); 77 } 78 79 public PreparedStatement prepareSelectStatement(String sql) 80 throws SQLException , HibernateException { 81 logOpenPreparedStatement(); 82 return getPreparedStatement( connectionManager.getConnection(), sql, false, false, null, false ); 83 } 84 85 public PreparedStatement prepareQueryStatement(String sql, boolean scrollable, ScrollMode scrollMode) 86 throws SQLException , HibernateException { 87 logOpenPreparedStatement(); 88 PreparedStatement ps = getPreparedStatement( connectionManager.getConnection(), sql, scrollable, scrollMode ); 89 setStatementFetchSize(ps); 90 statementsToClose.add(ps); 91 lastQuery=ps; 92 return ps; 93 } 94 95 public CallableStatement prepareCallableQueryStatement(String sql, boolean scrollable, ScrollMode scrollMode) 96 throws SQLException , HibernateException { 97 logOpenPreparedStatement(); 98 CallableStatement ps = (CallableStatement ) getPreparedStatement(connectionManager.getConnection(), sql, scrollable, false, scrollMode, true); 99 setStatementFetchSize(ps); 100 statementsToClose.add(ps); 101 lastQuery=ps; 102 return ps; 103 } 104 105 public void abortBatch(SQLException sqle) { 106 try { 107 if (batchUpdate!=null) closeStatement(batchUpdate); 108 } 109 catch (SQLException e) { 110 JDBCExceptionReporter.logExceptions(e); 112 } 113 finally { 114 batchUpdate=null; 115 batchUpdateSQL=null; 116 } 117 } 118 119 public ResultSet getResultSet(PreparedStatement ps) throws SQLException { 120 ResultSet rs = ps.executeQuery(); 121 resultSetsToClose.add(rs); 122 logOpenResults(); 123 return rs; 124 } 125 126 public ResultSet getResultSet(CallableStatement ps, Dialect dialect) throws SQLException { 127 ResultSet rs = dialect.getResultSet(ps); 128 resultSetsToClose.add(rs); 129 logOpenResults(); 130 return rs; 131 132 } 133 public void closeQueryStatement(PreparedStatement ps, ResultSet rs) throws SQLException { 134 statementsToClose.remove(ps); 135 if (rs!=null) resultSetsToClose.remove(rs); 136 try { 137 if (rs!=null) { 138 logCloseResults(); 139 rs.close(); 140 } 141 } 142 finally { 143 closeQueryStatement(ps); 144 } 145 } 146 147 public PreparedStatement prepareBatchStatement(String sql) 148 throws SQLException , HibernateException { 149 if ( !sql.equals(batchUpdateSQL) ) { 150 batchUpdate=prepareStatement(sql); batchUpdateSQL=sql; 152 } 153 else { 154 log.debug("reusing prepared statement"); 155 log(sql); 156 } 157 return batchUpdate; 158 } 159 160 public CallableStatement prepareBatchCallableStatement(String sql) 161 throws SQLException , HibernateException { 162 if ( !sql.equals(batchUpdateSQL) ) { batchUpdate=prepareCallableStatement(sql); batchUpdateSQL=sql; 165 } 166 return (CallableStatement )batchUpdate; 167 } 168 169 170 public void executeBatch() throws HibernateException { 171 if (batchUpdate!=null) { 172 try { 173 try { 174 doExecuteBatch(batchUpdate); 175 } 176 finally { 177 closeStatement(batchUpdate); 178 } 179 } 180 catch (SQLException sqle) { 181 throw JDBCExceptionHelper.convert( 182 factory.getSQLExceptionConverter(), 183 sqle, 184 "Could not execute JDBC batch update", 185 batchUpdateSQL 186 ); 187 } 188 finally { 189 batchUpdate=null; 190 batchUpdateSQL=null; 191 } 192 } 193 } 194 195 public void closeStatement(PreparedStatement ps) throws SQLException { 196 logClosePreparedStatement(); 197 closePreparedStatement(ps); 198 } 199 200 private void closeQueryStatement(PreparedStatement ps) throws SQLException { 201 202 try { 203 if ( ps.getMaxRows()!=0 ) ps.setMaxRows(0); 205 if ( ps.getQueryTimeout()!=0 ) ps.setQueryTimeout(0); 206 } 207 catch (Exception e) { 208 log.warn("exception clearing maxRows/queryTimeout", e); 209 return; } 212 finally { 213 closeStatement(ps); 214 } 215 216 if ( lastQuery==ps ) lastQuery = null; 217 218 } 219 220 224 public void closeStatements() { 225 try { 226 releasing = true; 227 228 try { 229 if (batchUpdate!=null) batchUpdate.close(); 230 } 231 catch (SQLException sqle) { 232 log.warn("Could not close a JDBC prepared statement", sqle); 234 } 235 batchUpdate=null; 236 batchUpdateSQL=null; 237 238 Iterator iter = resultSetsToClose.iterator(); 239 while ( iter.hasNext() ) { 240 try { 241 logCloseResults(); 242 ( (ResultSet ) iter.next() ).close(); 243 } 244 catch (SQLException e) { 245 log.warn("Could not close a JDBC result set", e); 247 } 248 } 249 resultSetsToClose.clear(); 250 251 iter = statementsToClose.iterator(); 252 while ( iter.hasNext() ) { 253 try { 254 closeQueryStatement( (PreparedStatement ) iter.next() ); 255 } 256 catch (SQLException e) { 257 log.warn("Could not close a JDBC statement", e); 259 } 260 } 261 statementsToClose.clear(); 262 } 263 finally { 264 releasing = false; 265 } 266 } 267 268 protected abstract void doExecuteBatch(PreparedStatement ps) throws SQLException , HibernateException; 269 270 private String preparedStatementCountsToString() { 271 return 272 " (open PreparedStatements: " + 273 openPreparedStatementCount + 274 ", globally: " + 275 globalOpenPreparedStatementCount + 276 ")"; 277 } 278 279 private String resultSetCountsToString() { 280 return 281 " (open ResultSets: " + 282 openResultSetCount + 283 ", globally: " + 284 globalOpenResultSetCount + 285 ")"; 286 } 287 288 private void logOpenPreparedStatement() { 289 if ( log.isDebugEnabled() ) { 290 log.debug( "about to open PreparedStatement" + preparedStatementCountsToString() ); 291 openPreparedStatementCount++; 292 globalOpenPreparedStatementCount++; 293 } 294 } 295 296 private void logClosePreparedStatement() { 297 if ( log.isDebugEnabled() ) { 298 log.debug( "about to close PreparedStatement" + preparedStatementCountsToString() ); 299 openPreparedStatementCount--; 300 globalOpenPreparedStatementCount--; 301 } 302 } 303 304 private void logOpenResults() { 305 if ( log.isDebugEnabled() ) { 306 log.debug( "about to open ResultSet" + resultSetCountsToString() ); 307 openResultSetCount++; 308 globalOpenResultSetCount++; 309 } 310 } 311 private void logCloseResults() { 312 if ( log.isDebugEnabled() ) { 313 log.debug( "about to close ResultSet" + resultSetCountsToString() ); 314 openResultSetCount--; 315 globalOpenResultSetCount--; 316 } 317 } 318 319 protected SessionFactoryImplementor getFactory() { 320 return factory; 321 } 322 323 private void log(String sql) { 324 SQL_LOG.debug(sql); 325 if ( factory.getSettings().isShowSqlEnabled() ) System.out.println("Hibernate: " + sql); 326 } 327 328 private PreparedStatement getPreparedStatement( 329 final Connection conn, 330 final String sql, 331 final boolean scrollable, 332 final ScrollMode scrollMode) 333 throws SQLException { 334 return getPreparedStatement(conn, sql, scrollable, false, scrollMode, false); 335 } 336 337 private CallableStatement getCallableStatement( final Connection conn, 338 final String sql, 339 boolean scrollable) 340 throws SQLException { 341 342 if ( scrollable && !factory.getSettings().isScrollableResultSetsEnabled() ) { 343 throw new AssertionFailure("scrollable result sets are not enabled"); 344 } 345 346 log(sql); 347 348 log.trace("preparing callable statement"); 349 if (scrollable) { 350 return conn.prepareCall(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); 351 } 352 else { 353 return conn.prepareCall(sql); 354 } 355 356 } 357 358 private PreparedStatement getPreparedStatement( 359 final Connection conn, 360 final String sql, 361 boolean scrollable, 362 final boolean useGetGeneratedKeys, 363 final ScrollMode scrollMode, 364 final boolean callable) 365 throws SQLException { 366 367 if ( scrollable && !factory.getSettings().isScrollableResultSetsEnabled() ) { 368 throw new AssertionFailure("scrollable result sets are not enabled"); 369 } 370 371 if ( useGetGeneratedKeys && !factory.getSettings().isGetGeneratedKeysEnabled() ) { 372 throw new AssertionFailure("getGeneratedKeys() support is not enabled"); 373 } 374 375 log(sql); 376 377 log.trace("preparing statement"); 378 PreparedStatement result; 379 if (scrollable) { 380 if (callable) { 381 result = conn.prepareCall( sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY ); 382 } 383 else { 384 result = conn.prepareStatement( sql, scrollMode.toResultSetType(), ResultSet.CONCUR_READ_ONLY ); 385 } 386 } 387 else if (useGetGeneratedKeys) { 388 result = GetGeneratedKeysHelper.prepareStatement(conn, sql); 389 } 390 else { 391 if (callable) { 392 result = conn.prepareCall(sql); 393 } 394 else { 395 result = conn.prepareStatement(sql); 396 } 397 } 398 399 if ( factory.getStatistics().isStatisticsEnabled() ) { 400 factory.getStatisticsImplementor().prepareStatement(); 401 } 402 403 return result; 404 405 } 406 407 private void closePreparedStatement(PreparedStatement ps) throws SQLException { 408 try { 409 log.trace("closing statement"); 410 ps.close(); 411 if ( factory.getStatistics().isStatisticsEnabled() ) { 412 factory.getStatisticsImplementor().closeStatement(); 413 } 414 } 415 finally { 416 if ( !releasing ) { 417 connectionManager.afterStatement(); 420 } 421 } 422 } 423 424 private void setStatementFetchSize(PreparedStatement statement) throws SQLException { 425 Integer statementFetchSize = factory.getSettings().getJdbcFetchSize(); 426 if ( statementFetchSize!=null ) { 427 statement.setFetchSize( statementFetchSize.intValue() ); 428 } 429 } 430 431 public Connection openConnection() throws HibernateException { 432 log.debug("opening JDBC connection"); 433 try { 434 return factory.getConnectionProvider().getConnection(); 435 } 436 catch (SQLException sqle) { 437 throw JDBCExceptionHelper.convert( 438 factory.getSQLExceptionConverter(), 439 sqle, 440 "Cannot open connection" 441 ); 442 } 443 } 444 445 public void closeConnection(Connection conn) throws HibernateException { 446 if ( log.isDebugEnabled() ) { 447 log.debug( 448 "closing JDBC connection" + 449 preparedStatementCountsToString() + 450 resultSetCountsToString() 451 ); 452 } 453 454 try { 455 if ( !conn.isClosed() ) { 456 JDBCExceptionReporter.logAndClearWarnings(conn); 457 } 458 factory.getConnectionProvider().closeConnection(conn); 459 } 460 catch (SQLException sqle) { 461 throw JDBCExceptionHelper.convert( 462 factory.getSQLExceptionConverter(), 463 sqle, 464 "Cannot close connection" 465 ); 466 } 467 } 468 469 public void cancelLastQuery() throws HibernateException { 470 try { 471 if (lastQuery!=null) lastQuery.cancel(); 472 } 473 catch (SQLException sqle) { 474 throw JDBCExceptionHelper.convert( 475 factory.getSQLExceptionConverter(), 476 sqle, 477 "Cannot cancel query" 478 ); 479 } 480 } 481 482 public boolean hasOpenResources() { 483 return resultSetsToClose.size() != 0 && statementsToClose.size() != 0; 484 } 485 486 public String openResourceStatsAsString() { 487 return preparedStatementCountsToString() + resultSetCountsToString(); 488 } 489 490 } 491 492 493 494 495 496 497 | Popular Tags |