diff --git a/src/jdbc/cubrid/jdbc/driver/CUBRIDConnection.java b/src/jdbc/cubrid/jdbc/driver/CUBRIDConnection.java index bb5bfed..c8f76be 100644 --- a/src/jdbc/cubrid/jdbc/driver/CUBRIDConnection.java +++ b/src/jdbc/cubrid/jdbc/driver/CUBRIDConnection.java @@ -35,6 +35,7 @@ import cubrid.jdbc.jci.UConnection; import cubrid.jdbc.jci.UError; import cubrid.jdbc.jci.UErrorCode; +import cubrid.jdbc.jci.UPreparedStatementCache; import cubrid.jdbc.jci.UStatement; import java.sql.Array; import java.sql.Blob; @@ -88,6 +89,7 @@ public class CUBRIDConnection implements Connection { protected CUBRIDShardMetaData shard_mdata; protected ArrayList outRs; private boolean isAutoGeneratedKeys = false; + protected UPreparedStatementCache prepStmtCache; /* * 3.0 ArrayList savepoints; int sv_count, sv_id; String sv_name; private @@ -109,6 +111,9 @@ public CUBRIDConnection(UConnection u, String r, String s) { statements = new ArrayList(); outRs = new ArrayList(); shard_mdata = null; + prepStmtCache = + new UPreparedStatementCache( + u_con.getPrepStmtCacheSize()); /* * 3.0 savepoints = new ArrayList(); sv_count = 0; sv_name = ""; @@ -811,6 +816,8 @@ protected PreparedStatement prepare( int resultHoldability, int autoGeneratedKeys) throws SQLException { + PreparedStatement pstmtCache = null; + checkIsOpen(); byte prepareFlag = (byte) 0; @@ -824,6 +831,13 @@ protected PreparedStatement prepare( prepareFlag = UConnection.PREPARE_HOLDABLE; } + if (u_con.isPrepStmtCache(sql)) { + pstmtCache = prepStmtCache.get(sql); + if (pstmtCache != null) { + return pstmtCache; + } + } + UStatement us = prepare(sql, prepareFlag); PreparedStatement pstmt = new CUBRIDPreparedStatement( @@ -835,6 +849,9 @@ protected PreparedStatement prepare( autoGeneratedKeys); addStatement(pstmt); + if (u_con.isPrepStmtCache(sql)) { + prepStmtCache.put(sql, pstmt); + } return pstmt; } diff --git a/src/jdbc/cubrid/jdbc/driver/CUBRIDPreparedStatement.java b/src/jdbc/cubrid/jdbc/driver/CUBRIDPreparedStatement.java index f988475..edeb63e 100644 --- a/src/jdbc/cubrid/jdbc/driver/CUBRIDPreparedStatement.java +++ b/src/jdbc/cubrid/jdbc/driver/CUBRIDPreparedStatement.java @@ -721,6 +721,8 @@ public void close() throws SQLException { try { synchronized (con) { synchronized (this) { + String sql = ""; + setShardId(UShardInfo.SHARD_ID_INVALID); if (is_closed) return; @@ -728,10 +730,15 @@ public void close() throws SQLException { is_closed = true; if (u_stmt != null) { + sql = u_stmt.getQuery(); u_stmt.close(); u_stmt = null; } + if (u_con.isPrepStmtCache(sql)) { + con.prepStmtCache.remove(sql); + } + con.removeStatement(this); con = null; u_con = null; diff --git a/src/jdbc/cubrid/jdbc/driver/ConnectionProperties.java b/src/jdbc/cubrid/jdbc/driver/ConnectionProperties.java index eb6441e..33eed86 100644 --- a/src/jdbc/cubrid/jdbc/driver/ConnectionProperties.java +++ b/src/jdbc/cubrid/jdbc/driver/ConnectionProperties.java @@ -395,6 +395,15 @@ private int getDefaultConnectTimeout() { BooleanConnectionProperty holdCursor = new BooleanConnectionProperty("hold_cursor", true); + BooleanConnectionProperty usePreparedStmtCache = + new BooleanConnectionProperty("usePreparedStmtCache", false); + + IntegerConnectionProperty preparedStmtCacheSize = + new IntegerConnectionProperty("preparedStmtCacheSize", 25, 1, Integer.MAX_VALUE); + + IntegerConnectionProperty preparedStmtCacheSqlLimit = + new IntegerConnectionProperty("preparedStmtCacheSqlLimit", 256, 1, Integer.MAX_VALUE); + public boolean getLogOnException() { return logOnException.getValueAsBoolean(); } @@ -470,4 +479,16 @@ public int getHoldCursor() { } return holdability; } + + public boolean getPrepStmtCache() { + return usePreparedStmtCache.getValueAsBoolean(); + } + + public int getPrepStmtCacheSize() { + return preparedStmtCacheSize.getValueAsInteger(); + } + + public int getPrepStmtCacheSqlLimit() { + return preparedStmtCacheSqlLimit.getValueAsInteger(); + } } diff --git a/src/jdbc/cubrid/jdbc/jci/UConnection.java b/src/jdbc/cubrid/jdbc/jci/UConnection.java index 058b280..55c9ffe 100644 --- a/src/jdbc/cubrid/jdbc/jci/UConnection.java +++ b/src/jdbc/cubrid/jdbc/jci/UConnection.java @@ -1490,6 +1490,27 @@ public int getClientCacheSize() { return connectionProperties.getClientCacheSize() * 1024 * 1024; } + public boolean getPrepStmtCache() { + return connectionProperties.getPrepStmtCache(); + } + + public int getPrepStmtCacheSize() { + return connectionProperties.getPrepStmtCacheSize(); + } + + public int getPrepStmtCacheSqlLimit() { + return connectionProperties.getPrepStmtCacheSqlLimit(); + } + + public boolean isPrepStmtCache(String sql) { + boolean isCacheable = false; + if (connectionProperties.getPrepStmtCache() + && sql.length() <= connectionProperties.getPrepStmtCacheSqlLimit()) { + isCacheable = true; + } + return isCacheable; + } + public void setCasIp(String casIp) { this.casIp = casIp; } diff --git a/src/jdbc/cubrid/jdbc/jci/UPreparedStatementCache.java b/src/jdbc/cubrid/jdbc/jci/UPreparedStatementCache.java new file mode 100644 index 0000000..014bc0f --- /dev/null +++ b/src/jdbc/cubrid/jdbc/jci/UPreparedStatementCache.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package cubrid.jdbc.jci; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +public class UPreparedStatementCache extends LinkedHashMap { + private static final long serialVersionUID = 1L; + protected int maxCacheSize; + + public UPreparedStatementCache(int maxCacheSize) { + super(maxCacheSize, 0.75F, true); + this.maxCacheSize = maxCacheSize; + } + + @Override + public V get(Object key) { + synchronized (this) { + return super.get(key); + } + } + + @Override + public V put(K key, V value) { + synchronized (this) { + return super.put(key, value); + } + } + + @Override + public V remove(Object key) { + synchronized (this) { + return super.remove(key); + } + } + + @Override + protected boolean removeEldestEntry(Entry eldest) { + return (size() > this.maxCacheSize); + } +}