From 6149affd88a252d68825ac56357b763aee450891 Mon Sep 17 00:00:00 2001 From: Brett Wooldridge Date: Wed, 12 Mar 2014 12:42:28 +0900 Subject: [PATCH] Support setting a default readOnly state for connections. --- .../java/com/zaxxer/hikari/HikariConfig.java | 11 ++ .../java/com/zaxxer/hikari/HikariPool.java | 8 +- .../zaxxer/hikari/proxy/ConnectionProxy.java | 142 ++++++++++++------ 3 files changed, 109 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/zaxxer/hikari/HikariConfig.java b/src/main/java/com/zaxxer/hikari/HikariConfig.java index ac1e20f6..1004424c 100644 --- a/src/main/java/com/zaxxer/hikari/HikariConfig.java +++ b/src/main/java/com/zaxxer/hikari/HikariConfig.java @@ -64,6 +64,7 @@ public class HikariConfig implements HikariConfigMBean private String catalog; private String poolName; private boolean isAutoCommit; + private boolean isReadOnly; private boolean isInitializationFailFast; private boolean isJdbc4connectionTest; private boolean isRegisterMbeans; @@ -327,6 +328,16 @@ public class HikariConfig implements HikariConfigMBean this.isJdbc4connectionTest = useIsValid; } + public boolean isReadOnly() + { + return isReadOnly; + } + + public void setReadOnly(boolean readOnly) + { + this.isReadOnly = readOnly; + } + public boolean isRegisterMbeans() { return isRegisterMbeans; diff --git a/src/main/java/com/zaxxer/hikari/HikariPool.java b/src/main/java/com/zaxxer/hikari/HikariPool.java index 3bc008e7..e76cba55 100644 --- a/src/main/java/com/zaxxer/hikari/HikariPool.java +++ b/src/main/java/com/zaxxer/hikari/HikariPool.java @@ -57,8 +57,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener private final long leakDetectionThreshold; private final AtomicInteger totalConnections; private final boolean isAutoCommit; - private final boolean jdbc4ConnectionTest; + private final boolean isReadOnly; private final boolean isRegisteredMbeans; + private final boolean jdbc4ConnectionTest; private final String catalog; private int transactionIsolation; private volatile boolean shutdown; @@ -82,6 +83,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener this.catalog = configuration.getCatalog(); this.connectionCustomizer = configuration.getConnectionCustomizer(); this.isAutoCommit = configuration.isAutoCommit(); + this.isReadOnly = configuration.isReadOnly(); this.isRegisteredMbeans = configuration.isRegisterMbeans(); this.jdbc4ConnectionTest = configuration.isJdbc4ConnectionTest(); this.leakDetectionThreshold = configuration.getLeakDetectionThreshold(); @@ -354,7 +356,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener connectionCustomizer.customize(connection); } - IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, transactionIsolation, isAutoCommit, catalog); + IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, transactionIsolation, isAutoCommit, isReadOnly, catalog); String initSql = configuration.getConnectionInitSql(); if (initSql != null && initSql.length() > 0) @@ -442,7 +444,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener { if (!isAutoCommit) { - connection.commit(); + connection.rollback(); } } diff --git a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java index 5d7255b3..ea356c18 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013,2014 Brett Wooldridge + * Copyright (C) 2013, 2014 Brett Wooldridge * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,14 +51,16 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy private final HikariPool parentPool; private final int defaultIsolationLevel; private final boolean defaultAutoCommit; + private final boolean defaultReadOnly; private final String defaultCatalog; private final AtomicInteger state; - private boolean isClosed; private boolean forceClose; - private boolean isTransactionIsolationDirty; private boolean isAutoCommitDirty; private boolean isCatalogDirty; + private boolean isClosed; + private boolean isReadOnlyDirty; + private boolean isTransactionIsolationDirty; private volatile long lastAccess; private StackTraceElement[] leakTrace; @@ -66,7 +68,6 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy private final int hashCode; - // static initializer static { @@ -79,12 +80,13 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy SQL_ERRORS.add("JZ0C1"); // Sybase disconnect error } - protected ConnectionProxy(HikariPool pool, Connection connection, int defaultIsolationLevel, boolean defaultAutoCommit, String defaultCatalog) + protected ConnectionProxy(HikariPool pool, Connection connection, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultReadOnly, String defaultCatalog) { this.parentPool = pool; this.delegate = connection; this.defaultIsolationLevel = defaultIsolationLevel; this.defaultAutoCommit = defaultAutoCommit; + this.defaultReadOnly = defaultReadOnly; this.defaultCatalog = defaultCatalog; this.state = new AtomicInteger(); @@ -93,41 +95,30 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy this.hashCode = System.identityHashCode(this); isCatalogDirty = true; + isReadOnlyDirty = true; isAutoCommitDirty = true; isTransactionIsolationDirty = true; } - public final void untrackStatement(Object statement) - { - // If the connection is not closed. If it is closed, it means this is being - // called back as a result of the close() method below in which case we - // will clear the openStatements collection en mass. - if (!isClosed) - { - openStatements.remove(statement); - } - } - - public final long getCreationTime() - { - return creationTime; - } - - public final long getLastAccess() + /** {@inheritDoc} */ + @Override + public final boolean equals(Object other) { - return lastAccess; + return this == other; } - public final void unclose() + /** {@inheritDoc} */ + @Override + public final int hashCode() { - isClosed = false; + return hashCode; } - public final void realClose() throws SQLException - { - delegate.close(); - } + // *********************************************************************** + // IHikariConnectionProxy methods + // *********************************************************************** + /** {@inheritDoc} */ public final void captureStack(long leakDetectionThreshold, Timer scheduler) { StackTraceElement[] trace = Thread.currentThread().getStackTrace(); @@ -138,11 +129,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy scheduler.schedule(leakTask, leakDetectionThreshold); } - public final boolean isBrokenConnection() - { - return forceClose; - } - + /** {@inheritDoc} */ public final void checkException(SQLException sqle) { String sqlState = sqle.getSQLState(); @@ -160,33 +147,31 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy } } - @Override - public final boolean equals(Object other) + /** {@inheritDoc} */ + public final long getCreationTime() { - return this == other; + return creationTime; } - @Override - public final int hashCode() + /** {@inheritDoc} */ + public final long getLastAccess() { - return hashCode; + return lastAccess; } - protected final void checkClosed() throws SQLException + /** {@inheritDoc} */ + public final boolean isBrokenConnection() { - if (isClosed) - { - throw new SQLException("Connection is closed"); - } + return forceClose; } - private T trackStatement(T statement) + /** {@inheritDoc} */ + public final void realClose() throws SQLException { - openStatements.add(statement); - - return statement; + delegate.close(); } + /** {@inheritDoc} */ public final void resetConnectionState() throws SQLException { if (!delegate.getAutoCommit()) @@ -194,6 +179,12 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy delegate.rollback(); } + if (isReadOnlyDirty) + { + delegate.setReadOnly(defaultReadOnly); + isReadOnlyDirty = false; + } + if (isAutoCommitDirty) { delegate.setAutoCommit(defaultAutoCommit); @@ -215,6 +206,43 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy delegate.clearWarnings(); } + /** {@inheritDoc} */ + public final void unclose() + { + isClosed = false; + } + + /** {@inheritDoc} */ + public final void untrackStatement(Object statement) + { + // If the connection is not closed. If it is closed, it means this is being + // called back as a result of the close() method below in which case we + // will clear the openStatements collection en mass. + if (!isClosed) + { + openStatements.remove(statement); + } + } + + // *********************************************************************** + // Internal methods + // *********************************************************************** + + protected final void checkClosed() throws SQLException + { + if (isClosed) + { + throw new SQLException("Connection is closed"); + } + } + + private T trackStatement(T statement) + { + openStatements.add(statement); + + return statement; + } + // ********************************************************************** // IBagManagable Methods // ********************************************************************** @@ -517,6 +545,22 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy } } + /** {@inheritDoc} */ + public final void setReadOnly(boolean readOnly) throws SQLException + { + checkClosed(); + try + { + delegate.setReadOnly(readOnly); + isReadOnlyDirty = (readOnly != defaultReadOnly); + } + catch (SQLException e) + { + checkException(e); + throw e; + } + } + /** {@inheritDoc} */ public final void setTransactionIsolation(int level) throws SQLException {