|
25 | 25 | */ |
26 | 26 | final class ConnectionPool implements DataSourcePool { |
27 | 27 |
|
| 28 | + enum CloseWithinTxn { |
| 29 | + NOTHING, ROLLBACK, COMMIT, FAIL, REMOVE; |
| 30 | + } |
| 31 | + |
28 | 32 | private static final String APPLICATION_NAME = "ApplicationName"; |
29 | 33 | private final ReentrantLock heartbeatLock = new ReentrantLock(false); |
30 | 34 | private final ReentrantLock notifyLock = new ReentrantLock(false); |
@@ -55,6 +59,7 @@ final class ConnectionPool implements DataSourcePool { |
55 | 59 | private final boolean failOnStart; |
56 | 60 | private final int maxInactiveMillis; |
57 | 61 | private final long validateStaleMillis; |
| 62 | + private final CloseWithinTxn closeWithinTxn; |
58 | 63 | /** |
59 | 64 | * Max age a connection is allowed in millis. |
60 | 65 | * A value of 0 means no limit (no trimming based on max age). |
@@ -94,6 +99,7 @@ final class ConnectionPool implements DataSourcePool { |
94 | 99 | private final boolean shutdownOnJvmExit; |
95 | 100 | private Thread shutdownHook; |
96 | 101 |
|
| 102 | + |
97 | 103 | ConnectionPool(String name, DataSourceConfig params) { |
98 | 104 | this.config = params; |
99 | 105 | this.name = name; |
@@ -128,10 +134,12 @@ final class ConnectionPool implements DataSourcePool { |
128 | 134 | this.user = params.getUsername(); |
129 | 135 | this.shutdownOnJvmExit = params.isShutdownOnJvmExit(); |
130 | 136 | this.source = DriverDataSource.of(name, params); |
| 137 | + this.closeWithinTxn = Enum.valueOf(CloseWithinTxn.class, params.closeWithinTxn().toUpperCase(Locale.ROOT)); |
131 | 138 | if (!params.isOffline()) { |
132 | 139 | init(); |
133 | 140 | } |
134 | 141 | this.nextTrimTime = System.currentTimeMillis() + trimPoolFreqMillis; |
| 142 | + |
135 | 143 | } |
136 | 144 |
|
137 | 145 | private void init() { |
@@ -516,6 +524,37 @@ boolean invalidConnection(PooledConnection conn) { |
516 | 524 | } |
517 | 525 | } |
518 | 526 |
|
| 527 | + /** |
| 528 | + * Fail hard in close() when there is uncommitted work. This is for debugging to find wrong code. |
| 529 | + */ |
| 530 | + boolean failIfWithinTransaction() { |
| 531 | + return closeWithinTxn == CloseWithinTxn.FAIL; |
| 532 | + } |
| 533 | + |
| 534 | + /** |
| 535 | + * will be called, before the connection is returned to the pool. This happens, when there may |
| 536 | + * be uncommitted changes and before all settings like autocommit/schema/catalog are reset to default. |
| 537 | + * <p> |
| 538 | + * If this method fails, the connection is silently removed from pool |
| 539 | + */ |
| 540 | + void closeWithinTxn(PooledConnection pooledConnection) throws SQLException { |
| 541 | + switch (closeWithinTxn) { |
| 542 | + case NOTHING: |
| 543 | + Log.trace("Closing active connection."); |
| 544 | + break; |
| 545 | + case ROLLBACK: |
| 546 | + pooledConnection.rollback(); |
| 547 | + Log.trace("Closing active connection. Rollback performed."); |
| 548 | + break; |
| 549 | + case COMMIT: |
| 550 | + pooledConnection.commit(); |
| 551 | + Log.trace("Closing active connection. Commit performed."); |
| 552 | + break; |
| 553 | + case REMOVE: |
| 554 | + throw new SQLException("Closing active connection. Removing from pool."); |
| 555 | + } |
| 556 | + } |
| 557 | + |
519 | 558 | /** |
520 | 559 | * Called by the PooledConnection themselves, returning themselves to the |
521 | 560 | * pool when they have been finished with. |
|
0 commit comments