• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / mybatis-3 / #2983

pending completion
#2983

push

github

web-flow
Merge pull request #2799 from hazendaz/formatting

[ci] Fix readme for formatter tags

9373 of 10751 relevant lines covered (87.18%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.1
/src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java
1
/*
2
 *    Copyright 2009-2023 the original author or authors.
3
 *
4
 *    Licensed under the Apache License, Version 2.0 (the "License");
5
 *    you may not use this file except in compliance with the License.
6
 *    You may obtain a copy of the License at
7
 *
8
 *       https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *    Unless required by applicable law or agreed to in writing, software
11
 *    distributed under the License is distributed on an "AS IS" BASIS,
12
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *    See the License for the specific language governing permissions and
14
 *    limitations under the License.
15
 */
16
package org.apache.ibatis.datasource.pooled;
17

18
import java.io.PrintWriter;
19
import java.lang.reflect.InvocationHandler;
20
import java.lang.reflect.Proxy;
21
import java.sql.Connection;
22
import java.sql.DriverManager;
23
import java.sql.SQLException;
24
import java.sql.Statement;
25
import java.util.Properties;
26
import java.util.concurrent.TimeUnit;
27
import java.util.concurrent.locks.Condition;
28
import java.util.concurrent.locks.Lock;
29
import java.util.concurrent.locks.ReentrantLock;
30
import java.util.logging.Logger;
31

32
import javax.sql.DataSource;
33

34
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
35
import org.apache.ibatis.logging.Log;
36
import org.apache.ibatis.logging.LogFactory;
37

38
/**
39
 * This is a simple, synchronous, thread-safe database connection pool.
40
 *
41
 * @author Clinton Begin
42
 */
43
public class PooledDataSource implements DataSource {
44

45
  private static final Log log = LogFactory.getLog(PooledDataSource.class);
1✔
46

47
  private final PoolState state = new PoolState(this);
1✔
48

49
  private final UnpooledDataSource dataSource;
50

51
  // OPTIONAL CONFIGURATION FIELDS
52
  protected int poolMaximumActiveConnections = 10;
1✔
53
  protected int poolMaximumIdleConnections = 5;
1✔
54
  protected int poolMaximumCheckoutTime = 20000;
1✔
55
  protected int poolTimeToWait = 20000;
1✔
56
  protected int poolMaximumLocalBadConnectionTolerance = 3;
1✔
57
  protected String poolPingQuery = "NO PING QUERY SET";
1✔
58
  protected boolean poolPingEnabled;
59
  protected int poolPingConnectionsNotUsedFor;
60

61
  private int expectedConnectionTypeCode;
62

63
  private final Lock lock = new ReentrantLock();
1✔
64
  private final Condition condition = lock.newCondition();
1✔
65

66
  public PooledDataSource() {
1✔
67
    dataSource = new UnpooledDataSource();
1✔
68
  }
1✔
69

70
  public PooledDataSource(UnpooledDataSource dataSource) {
×
71
    this.dataSource = dataSource;
×
72
  }
×
73

74
  public PooledDataSource(String driver, String url, String username, String password) {
×
75
    dataSource = new UnpooledDataSource(driver, url, username, password);
×
76
    expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(),
×
77
        dataSource.getPassword());
×
78
  }
×
79

80
  public PooledDataSource(String driver, String url, Properties driverProperties) {
×
81
    dataSource = new UnpooledDataSource(driver, url, driverProperties);
×
82
    expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(),
×
83
        dataSource.getPassword());
×
84
  }
×
85

86
  public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {
×
87
    dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password);
×
88
    expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(),
×
89
        dataSource.getPassword());
×
90
  }
×
91

92
  public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
×
93
    dataSource = new UnpooledDataSource(driverClassLoader, driver, url, driverProperties);
×
94
    expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(),
×
95
        dataSource.getPassword());
×
96
  }
×
97

98
  @Override
99
  public Connection getConnection() throws SQLException {
100
    return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
1✔
101
  }
102

103
  @Override
104
  public Connection getConnection(String username, String password) throws SQLException {
105
    return popConnection(username, password).getProxyConnection();
×
106
  }
107

108
  @Override
109
  public void setLoginTimeout(int loginTimeout) {
110
    DriverManager.setLoginTimeout(loginTimeout);
×
111
  }
×
112

113
  @Override
114
  public int getLoginTimeout() {
115
    return DriverManager.getLoginTimeout();
×
116
  }
117

118
  @Override
119
  public void setLogWriter(PrintWriter logWriter) {
120
    DriverManager.setLogWriter(logWriter);
1✔
121
  }
1✔
122

123
  @Override
124
  public PrintWriter getLogWriter() {
125
    return DriverManager.getLogWriter();
×
126
  }
127

128
  public void setDriver(String driver) {
129
    dataSource.setDriver(driver);
1✔
130
    forceCloseAll();
1✔
131
  }
1✔
132

133
  public void setUrl(String url) {
134
    dataSource.setUrl(url);
1✔
135
    forceCloseAll();
1✔
136
  }
1✔
137

138
  public void setUsername(String username) {
139
    dataSource.setUsername(username);
1✔
140
    forceCloseAll();
1✔
141
  }
1✔
142

143
  public void setPassword(String password) {
144
    dataSource.setPassword(password);
1✔
145
    forceCloseAll();
1✔
146
  }
1✔
147

148
  public void setDefaultAutoCommit(boolean defaultAutoCommit) {
149
    dataSource.setAutoCommit(defaultAutoCommit);
1✔
150
    forceCloseAll();
1✔
151
  }
1✔
152

153
  public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) {
154
    dataSource.setDefaultTransactionIsolationLevel(defaultTransactionIsolationLevel);
×
155
    forceCloseAll();
×
156
  }
×
157

158
  public void setDriverProperties(Properties driverProps) {
159
    dataSource.setDriverProperties(driverProps);
1✔
160
    forceCloseAll();
1✔
161
  }
1✔
162

163
  /**
164
   * Sets the default network timeout value to wait for the database operation to complete. See
165
   * {@link Connection#setNetworkTimeout(java.util.concurrent.Executor, int)}
166
   *
167
   * @param milliseconds
168
   *          The time in milliseconds to wait for the database operation to complete.
169
   *
170
   * @since 3.5.2
171
   */
172
  public void setDefaultNetworkTimeout(Integer milliseconds) {
173
    dataSource.setDefaultNetworkTimeout(milliseconds);
×
174
    forceCloseAll();
×
175
  }
×
176

177
  /**
178
   * The maximum number of active connections.
179
   *
180
   * @param poolMaximumActiveConnections
181
   *          The maximum number of active connections
182
   */
183
  public void setPoolMaximumActiveConnections(int poolMaximumActiveConnections) {
184
    this.poolMaximumActiveConnections = poolMaximumActiveConnections;
1✔
185
    forceCloseAll();
1✔
186
  }
1✔
187

188
  /**
189
   * The maximum number of idle connections.
190
   *
191
   * @param poolMaximumIdleConnections
192
   *          The maximum number of idle connections
193
   */
194
  public void setPoolMaximumIdleConnections(int poolMaximumIdleConnections) {
195
    this.poolMaximumIdleConnections = poolMaximumIdleConnections;
1✔
196
    forceCloseAll();
1✔
197
  }
1✔
198

199
  /**
200
   * The maximum number of tolerance for bad connection happens in one thread which are applying for new
201
   * {@link PooledConnection}.
202
   *
203
   * @param poolMaximumLocalBadConnectionTolerance
204
   *          max tolerance for bad connection happens in one thread
205
   *
206
   * @since 3.4.5
207
   */
208
  public void setPoolMaximumLocalBadConnectionTolerance(int poolMaximumLocalBadConnectionTolerance) {
209
    this.poolMaximumLocalBadConnectionTolerance = poolMaximumLocalBadConnectionTolerance;
×
210
  }
×
211

212
  /**
213
   * The maximum time a connection can be used before it *may* be given away again.
214
   *
215
   * @param poolMaximumCheckoutTime
216
   *          The maximum time
217
   */
218
  public void setPoolMaximumCheckoutTime(int poolMaximumCheckoutTime) {
219
    this.poolMaximumCheckoutTime = poolMaximumCheckoutTime;
1✔
220
    forceCloseAll();
1✔
221
  }
1✔
222

223
  /**
224
   * The time to wait before retrying to get a connection.
225
   *
226
   * @param poolTimeToWait
227
   *          The time to wait
228
   */
229
  public void setPoolTimeToWait(int poolTimeToWait) {
230
    this.poolTimeToWait = poolTimeToWait;
1✔
231
    forceCloseAll();
1✔
232
  }
1✔
233

234
  /**
235
   * The query to be used to check a connection.
236
   *
237
   * @param poolPingQuery
238
   *          The query
239
   */
240
  public void setPoolPingQuery(String poolPingQuery) {
241
    this.poolPingQuery = poolPingQuery;
1✔
242
    forceCloseAll();
1✔
243
  }
1✔
244

245
  /**
246
   * Determines if the ping query should be used.
247
   *
248
   * @param poolPingEnabled
249
   *          True if we need to check a connection before using it
250
   */
251
  public void setPoolPingEnabled(boolean poolPingEnabled) {
252
    this.poolPingEnabled = poolPingEnabled;
1✔
253
    forceCloseAll();
1✔
254
  }
1✔
255

256
  /**
257
   * If a connection has not been used in this many milliseconds, ping the database to make sure the connection is still
258
   * good.
259
   *
260
   * @param milliseconds
261
   *          the number of milliseconds of inactivity that will trigger a ping
262
   */
263
  public void setPoolPingConnectionsNotUsedFor(int milliseconds) {
264
    this.poolPingConnectionsNotUsedFor = milliseconds;
1✔
265
    forceCloseAll();
1✔
266
  }
1✔
267

268
  public String getDriver() {
269
    return dataSource.getDriver();
1✔
270
  }
271

272
  public String getUrl() {
273
    return dataSource.getUrl();
1✔
274
  }
275

276
  public String getUsername() {
277
    return dataSource.getUsername();
1✔
278
  }
279

280
  public String getPassword() {
281
    return dataSource.getPassword();
1✔
282
  }
283

284
  public boolean isAutoCommit() {
285
    return dataSource.isAutoCommit();
×
286
  }
287

288
  public Integer getDefaultTransactionIsolationLevel() {
289
    return dataSource.getDefaultTransactionIsolationLevel();
×
290
  }
291

292
  public Properties getDriverProperties() {
293
    return dataSource.getDriverProperties();
×
294
  }
295

296
  /**
297
   * Gets the default network timeout.
298
   *
299
   * @return the default network timeout
300
   *
301
   * @since 3.5.2
302
   */
303
  public Integer getDefaultNetworkTimeout() {
304
    return dataSource.getDefaultNetworkTimeout();
×
305
  }
306

307
  public int getPoolMaximumActiveConnections() {
308
    return poolMaximumActiveConnections;
×
309
  }
310

311
  public int getPoolMaximumIdleConnections() {
312
    return poolMaximumIdleConnections;
×
313
  }
314

315
  public int getPoolMaximumLocalBadConnectionTolerance() {
316
    return poolMaximumLocalBadConnectionTolerance;
×
317
  }
318

319
  public int getPoolMaximumCheckoutTime() {
320
    return poolMaximumCheckoutTime;
×
321
  }
322

323
  public int getPoolTimeToWait() {
324
    return poolTimeToWait;
×
325
  }
326

327
  public String getPoolPingQuery() {
328
    return poolPingQuery;
×
329
  }
330

331
  public boolean isPoolPingEnabled() {
332
    return poolPingEnabled;
×
333
  }
334

335
  public int getPoolPingConnectionsNotUsedFor() {
336
    return poolPingConnectionsNotUsedFor;
×
337
  }
338

339
  /**
340
   * Closes all active and idle connections in the pool.
341
   */
342
  public void forceCloseAll() {
343
    lock.lock();
1✔
344
    try {
345
      expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(),
1✔
346
          dataSource.getPassword());
1✔
347
      for (int i = state.activeConnections.size(); i > 0; i--) {
1✔
348
        try {
349
          PooledConnection conn = state.activeConnections.remove(i - 1);
×
350
          conn.invalidate();
×
351

352
          Connection realConn = conn.getRealConnection();
×
353
          if (!realConn.getAutoCommit()) {
×
354
            realConn.rollback();
×
355
          }
356
          realConn.close();
×
357
        } catch (Exception e) {
×
358
          // ignore
359
        }
×
360
      }
361
      for (int i = state.idleConnections.size(); i > 0; i--) {
1✔
362
        try {
363
          PooledConnection conn = state.idleConnections.remove(i - 1);
1✔
364
          conn.invalidate();
1✔
365

366
          Connection realConn = conn.getRealConnection();
1✔
367
          if (!realConn.getAutoCommit()) {
1✔
368
            realConn.rollback();
1✔
369
          }
370
          realConn.close();
1✔
371
        } catch (Exception e) {
×
372
          // ignore
373
        }
1✔
374
      }
375
    } finally {
376
      lock.unlock();
1✔
377
    }
378
    if (log.isDebugEnabled()) {
1✔
379
      log.debug("PooledDataSource forcefully closed/removed all connections.");
×
380
    }
381
  }
1✔
382

383
  public PoolState getPoolState() {
384
    return state;
1✔
385
  }
386

387
  private int assembleConnectionTypeCode(String url, String username, String password) {
388
    return ("" + url + username + password).hashCode();
1✔
389
  }
390

391
  protected void pushConnection(PooledConnection conn) throws SQLException {
392

393
    lock.lock();
1✔
394
    try {
395
      state.activeConnections.remove(conn);
1✔
396
      if (conn.isValid()) {
1✔
397
        if (state.idleConnections.size() < poolMaximumIdleConnections
1✔
398
            && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
1✔
399
          state.accumulatedCheckoutTime += conn.getCheckoutTime();
1✔
400
          if (!conn.getRealConnection().getAutoCommit()) {
1✔
401
            conn.getRealConnection().rollback();
1✔
402
          }
403
          PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
1✔
404
          state.idleConnections.add(newConn);
1✔
405
          newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
1✔
406
          newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
1✔
407
          conn.invalidate();
1✔
408
          if (log.isDebugEnabled()) {
1✔
409
            log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
×
410
          }
411
          condition.signal();
1✔
412
        } else {
1✔
413
          state.accumulatedCheckoutTime += conn.getCheckoutTime();
1✔
414
          if (!conn.getRealConnection().getAutoCommit()) {
1✔
415
            conn.getRealConnection().rollback();
1✔
416
          }
417
          conn.getRealConnection().close();
1✔
418
          if (log.isDebugEnabled()) {
1✔
419
            log.debug("Closed connection " + conn.getRealHashCode() + ".");
×
420
          }
421
          conn.invalidate();
1✔
422
        }
423
      } else {
424
        if (log.isDebugEnabled()) {
1✔
425
          log.debug("A bad connection (" + conn.getRealHashCode()
×
426
              + ") attempted to return to the pool, discarding connection.");
427
        }
428
        state.badConnectionCount++;
1✔
429
      }
430
    } finally {
431
      lock.unlock();
1✔
432
    }
433
  }
1✔
434

435
  private PooledConnection popConnection(String username, String password) throws SQLException {
436
    boolean countedWait = false;
1✔
437
    PooledConnection conn = null;
1✔
438
    long t = System.currentTimeMillis();
1✔
439
    int localBadConnectionCount = 0;
1✔
440

441
    while (conn == null) {
1✔
442
      lock.lock();
1✔
443
      try {
444
        if (!state.idleConnections.isEmpty()) {
1✔
445
          // Pool has available connection
446
          conn = state.idleConnections.remove(0);
×
447
          if (log.isDebugEnabled()) {
×
448
            log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
×
449
          }
450
        } else {
451
          // Pool does not have available connection
452
          if (state.activeConnections.size() < poolMaximumActiveConnections) {
1✔
453
            // Can create new connection
454
            conn = new PooledConnection(dataSource.getConnection(), this);
1✔
455
            if (log.isDebugEnabled()) {
1✔
456
              log.debug("Created connection " + conn.getRealHashCode() + ".");
×
457
            }
458
          } else {
459
            // Cannot create new connection
460
            PooledConnection oldestActiveConnection = state.activeConnections.get(0);
×
461
            long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
×
462
            if (longestCheckoutTime > poolMaximumCheckoutTime) {
×
463
              // Can claim overdue connection
464
              state.claimedOverdueConnectionCount++;
×
465
              state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
×
466
              state.accumulatedCheckoutTime += longestCheckoutTime;
×
467
              state.activeConnections.remove(oldestActiveConnection);
×
468
              if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
×
469
                try {
470
                  oldestActiveConnection.getRealConnection().rollback();
×
471
                } catch (SQLException e) {
×
472
                  /*
473
                   * Just log a message for debug and continue to execute the following statement like nothing happened.
474
                   * Wrap the bad connection with a new PooledConnection, this will help to not interrupt current
475
                   * executing thread and give current thread a chance to join the next competition for another
476
                   * valid/good database connection. At the end of this loop, bad {@link @conn} will be set as null.
477
                   */
478
                  log.debug("Bad connection. Could not roll back");
×
479
                }
×
480
              }
481
              conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
×
482
              conn.setCreatedTimestamp(oldestActiveConnection.getCreatedTimestamp());
×
483
              conn.setLastUsedTimestamp(oldestActiveConnection.getLastUsedTimestamp());
×
484
              oldestActiveConnection.invalidate();
×
485
              if (log.isDebugEnabled()) {
×
486
                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
×
487
              }
488
            } else {
489
              // Must wait
490
              try {
491
                if (!countedWait) {
×
492
                  state.hadToWaitCount++;
×
493
                  countedWait = true;
×
494
                }
495
                if (log.isDebugEnabled()) {
×
496
                  log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
×
497
                }
498
                long wt = System.currentTimeMillis();
×
499
                condition.await(poolTimeToWait, TimeUnit.MILLISECONDS);
×
500
                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
×
501
              } catch (InterruptedException e) {
×
502
                // set interrupt flag
503
                Thread.currentThread().interrupt();
×
504
                break;
505
              }
×
506
            }
507
          }
508
        }
509
        if (conn != null) {
1✔
510
          // ping to server and check the connection is valid or not
511
          if (conn.isValid()) {
1✔
512
            if (!conn.getRealConnection().getAutoCommit()) {
1✔
513
              conn.getRealConnection().rollback();
1✔
514
            }
515
            conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
1✔
516
            conn.setCheckoutTimestamp(System.currentTimeMillis());
1✔
517
            conn.setLastUsedTimestamp(System.currentTimeMillis());
1✔
518
            state.activeConnections.add(conn);
1✔
519
            state.requestCount++;
1✔
520
            state.accumulatedRequestTime += System.currentTimeMillis() - t;
1✔
521
          } else {
522
            if (log.isDebugEnabled()) {
×
523
              log.debug("A bad connection (" + conn.getRealHashCode()
×
524
                  + ") was returned from the pool, getting another connection.");
525
            }
526
            state.badConnectionCount++;
×
527
            localBadConnectionCount++;
×
528
            conn = null;
×
529
            if (localBadConnectionCount > (poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance)) {
×
530
              if (log.isDebugEnabled()) {
×
531
                log.debug("PooledDataSource: Could not get a good connection to the database.");
×
532
              }
533
              throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
×
534
            }
535
          }
536
        }
537
      } finally {
538
        lock.unlock();
1✔
539
      }
1✔
540

541
    }
542

543
    if (conn == null) {
1✔
544
      if (log.isDebugEnabled()) {
×
545
        log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
×
546
      }
547
      throw new SQLException(
×
548
          "PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
549
    }
550

551
    return conn;
1✔
552
  }
553

554
  /**
555
   * Method to check to see if a connection is still usable
556
   *
557
   * @param conn
558
   *          - the connection to check
559
   *
560
   * @return True if the connection is still usable
561
   */
562
  protected boolean pingConnection(PooledConnection conn) {
563
    boolean result = true;
1✔
564

565
    try {
566
      result = !conn.getRealConnection().isClosed();
1✔
567
    } catch (SQLException e) {
×
568
      if (log.isDebugEnabled()) {
×
569
        log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
×
570
      }
571
      result = false;
×
572
    }
1✔
573

574
    if (result && poolPingEnabled && poolPingConnectionsNotUsedFor >= 0
1✔
575
        && conn.getTimeElapsedSinceLastUse() > poolPingConnectionsNotUsedFor) {
1✔
576
      try {
577
        if (log.isDebugEnabled()) {
×
578
          log.debug("Testing connection " + conn.getRealHashCode() + " ...");
×
579
        }
580
        Connection realConn = conn.getRealConnection();
×
581
        try (Statement statement = realConn.createStatement()) {
×
582
          statement.executeQuery(poolPingQuery).close();
×
583
        }
584
        if (!realConn.getAutoCommit()) {
×
585
          realConn.rollback();
×
586
        }
587
        result = true;
×
588
        if (log.isDebugEnabled()) {
×
589
          log.debug("Connection " + conn.getRealHashCode() + " is GOOD!");
×
590
        }
591
      } catch (Exception e) {
×
592
        log.warn("Execution of ping query '" + poolPingQuery + "' failed: " + e.getMessage());
×
593
        try {
594
          conn.getRealConnection().close();
×
595
        } catch (Exception e2) {
×
596
          // ignore
597
        }
×
598
        result = false;
×
599
        if (log.isDebugEnabled()) {
×
600
          log.debug("Connection " + conn.getRealHashCode() + " is BAD: " + e.getMessage());
×
601
        }
602
      }
×
603
    }
604
    return result;
1✔
605
  }
606

607
  /**
608
   * Unwraps a pooled connection to get to the 'real' connection
609
   *
610
   * @param conn
611
   *          - the pooled connection to unwrap
612
   *
613
   * @return The 'real' connection
614
   */
615
  public static Connection unwrapConnection(Connection conn) {
616
    if (Proxy.isProxyClass(conn.getClass())) {
1✔
617
      InvocationHandler handler = Proxy.getInvocationHandler(conn);
1✔
618
      if (handler instanceof PooledConnection) {
1✔
619
        return ((PooledConnection) handler).getRealConnection();
1✔
620
      }
621
    }
622
    return conn;
×
623
  }
624

625
  @Override
626
  protected void finalize() throws Throwable {
627
    forceCloseAll();
1✔
628
    super.finalize();
1✔
629
  }
1✔
630

631
  @Override
632
  public <T> T unwrap(Class<T> iface) throws SQLException {
633
    throw new SQLException(getClass().getName() + " is not a wrapper.");
×
634
  }
635

636
  @Override
637
  public boolean isWrapperFor(Class<?> iface) {
638
    return false;
×
639
  }
640

641
  @Override
642
  public Logger getParentLogger() {
643
    return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
×
644
  }
645

646
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc