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

mybatis / mybatis-3 / #3393

25 Dec 2023 01:42AM UTC coverage: 86.665% (+0.05%) from 86.619%
#3393

Pull #2971

github

web-flow
Merge 9b99f44b6 into 01225f508
Pull Request #2971: docs: add dynamic sql example to @Select

3498 of 4275 branches covered (0.0%)

9294 of 10724 relevant lines covered (86.67%)

0.87 hits per line

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

64.58
/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) {
1✔
75
    dataSource = new UnpooledDataSource(driver, url, username, password);
1✔
76
    expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(),
1✔
77
        dataSource.getPassword());
1✔
78
  }
1✔
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;
1✔
309
  }
310

311
  public int getPoolMaximumIdleConnections() {
312
    return poolMaximumIdleConnections;
1✔
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);
1✔
350
          conn.invalidate();
1✔
351

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

540
    }
541

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

550
    return conn;
1✔
551
  }
552

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

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

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

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

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

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

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

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

644
}
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