package com.moparisthebest.jdbc; import com.moparisthebest.jdbc.util.ResultSetIterable; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; //IFJAVA8_START import java.util.stream.Stream; //IFJAVA8_END import static com.moparisthebest.jdbc.TryClose.tryClose; /** * This class caches the PreparedStatement's it creates for the strings you send in, then closes them when the close() method is called. * Since PreparedStatement is not thread-safe, this class cannot be either. Be sure to call it from only a single thread * or synchronize around it. */ public class CachingQueryMapper extends QueryMapper { protected final Map cache; protected CachingQueryMapper(Connection conn, String jndiName, Factory factory, ResultSetMapper cm, final int maxEntries) { super(conn, jndiName, factory, cm); if (maxEntries > 0) { // we want a limited cache final float loadFactor = 0.75f; // default for HashMaps // if we set the initialCapacity this way, nothing should ever need re-sized final int initialCapacity = ((int) Math.ceil(maxEntries / loadFactor)) + 1; cache = new LinkedHashMap(initialCapacity, loadFactor, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { final boolean remove = size() > maxEntries; if(remove){ //System.out.printf("closing PreparedStatement '%s' with key '%s'\n", eldest.getValue(), eldest.getKey()); tryClose(eldest.getValue()); } return remove; } }; } else cache = new HashMap(); } protected CachingQueryMapper(Connection conn, String jndiName, Factory factory, ResultSetMapper cm) { this(conn, jndiName, factory, cm, 20); // default size of 20 } public CachingQueryMapper(Connection conn, ResultSetMapper cm, final int maxEntries) { this(conn, null, null, cm, maxEntries); } public CachingQueryMapper(Connection conn, final int maxEntries) { this(conn, null, null, null, maxEntries); } public CachingQueryMapper(String jndiName, ResultSetMapper cm, final int maxEntries) { this(null, jndiName, null, cm, maxEntries); } public CachingQueryMapper(String jndiName, final int maxEntries) { this(null, jndiName, null, null, maxEntries); } public CachingQueryMapper(Factory factory, ResultSetMapper cm, final int maxEntries) { this(null, null, factory, cm, maxEntries); } public CachingQueryMapper(Factory factory, final int maxEntries) { this(null, null, factory, null, maxEntries); } public CachingQueryMapper(Connection conn, ResultSetMapper cm) { this(conn, null, null, cm); } public CachingQueryMapper(Connection conn) { this(conn, null, null, null); } public CachingQueryMapper(String jndiName, ResultSetMapper cm) { this(null, jndiName, null, cm); } public CachingQueryMapper(String jndiName) { this(null, jndiName, null, null); } public CachingQueryMapper(Factory factory, ResultSetMapper cm) { this(null, null, factory, cm); } public CachingQueryMapper(Factory factory) { this(null, null, factory, null); } protected PreparedStatement getPreparedStatement(String sql) throws SQLException { return getPreparedStatement(sql, ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY); } protected PreparedStatement getPreparedStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { PreparedStatement ps = cache.get(sql); if (ps == null) { //System.out.println("cache miss"); ps = conn.prepareStatement(sql,resultSetType,resultSetConcurrency); cache.put(sql, ps); } //else System.out.println("cache hit"); return ps; } public void clearCache(boolean close) { //System.out.println("cache size: "+cache.size()); for (PreparedStatement ps : cache.values()) tryClose(ps); if (close) super.close(); else cache.clear(); } public void clearCache() { this.clearCache(false); } @Override public void close() { this.clearCache(true); } @Override public int executeUpdate(String sql, Object... bindObjects) throws SQLException { return super.executeUpdate(getPreparedStatement(sql), bindObjects); } @Override public boolean executeUpdateSuccess(String sql, Object... bindObjects) throws SQLException { return super.executeUpdateSuccess(getPreparedStatement(sql), bindObjects); } // these grab ResultSets from the database @Override public ResultSet toResultSet(String sql, Object... bindObjects) throws SQLException { return super.toResultSet(getPreparedStatement(sql), bindObjects); } @Override public ResultSet toResultSet(String sql, Integer rsType, Integer rsConcurrency, Object... bindObjects) throws SQLException { return super.toResultSet(getPreparedStatement(sql,rsType,rsConcurrency), bindObjects); } // DO NOT EDIT BELOW THIS LINE, OR CHANGE THIS COMMENT, CODE AUTOMATICALLY GENERATED BY genQueryMapper.sh @Override public T toObject(String sql, Class componentType, final Object... bindObjects) throws SQLException { return super.toObject(getPreparedStatement(sql), componentType, bindObjects); } @Override public ResultSetIterable toResultSetIterable(String sql, Class componentType, final Object... bindObjects) throws SQLException { return super.toResultSetIterable(getPreparedStatement(sql), componentType, bindObjects); } @Override public , V> ResultSetIterable> toResultSetIterable(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toResultSetIterable(getPreparedStatement(sql), componentType, mapValType, bindObjects); } //IFJAVA8_START @Override public Stream toStream(String sql, Class componentType, final Object... bindObjects) throws SQLException { return super.toStream(getPreparedStatement(sql), componentType, bindObjects); } //IFJAVA8_END //IFJAVA8_START @Override public , V> Stream> toStream(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toStream(getPreparedStatement(sql), componentType, mapValType, bindObjects); } //IFJAVA8_END @Override public , V> Map toSingleMap(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toSingleMap(getPreparedStatement(sql), componentType, mapValType, bindObjects); } @Override public Map toSingleMap(String sql, Class mapValType, final Object... bindObjects) throws SQLException { return super.toSingleMap(getPreparedStatement(sql), mapValType, bindObjects); } @Override public T toType(String sql, TypeReference typeReference, final Object... bindObjects) throws SQLException { return super.toType(getPreparedStatement(sql), typeReference, bindObjects); } @Override public , E> T toCollection(String sql, final Class collectionType, Class componentType, final Object... bindObjects) throws SQLException { return super.toCollection(getPreparedStatement(sql), collectionType, componentType, bindObjects); } @Override public , E> T toCollection(String sql, T list, Class componentType, final Object... bindObjects) throws SQLException { return super.toCollection(getPreparedStatement(sql), list, componentType, bindObjects); } @Override public , K, E> T toMap(String sql, T map, Class mapKeyType, Class componentType, final Object... bindObjects) throws SQLException { return super.toMap(getPreparedStatement(sql), map, mapKeyType, componentType, bindObjects); } @Override public , K, E extends Collection, C> T toMapCollection(String sql, final Class returnType, Class mapKeyType, Class collectionType, Class componentType, final Object... bindObjects) throws SQLException { return super.toMapCollection(getPreparedStatement(sql), returnType, mapKeyType, collectionType, componentType, bindObjects); } @Override public , K, E extends Collection, C> T toMapCollection(String sql, T map, Class mapKeyType, Class collectionType, Class componentType, final Object... bindObjects) throws SQLException { return super.toMapCollection(getPreparedStatement(sql), map, mapKeyType, collectionType, componentType, bindObjects); } @Override public ListIterator toListIterator(String sql, final Class type, final Object... bindObjects) throws SQLException { return super.toListIterator(getPreparedStatement(sql), type, bindObjects); } @Override public Iterator toIterator(String sql, final Class type, final Object... bindObjects) throws SQLException { return super.toIterator(getPreparedStatement(sql), type, bindObjects); } @Override public T[] toArray(String sql, final Class type, final Object... bindObjects) throws SQLException { return super.toArray(getPreparedStatement(sql), type, bindObjects); } @Override public List toList(String sql, Class componentType, final Object... bindObjects) throws SQLException { return super.toList(getPreparedStatement(sql), componentType, bindObjects); } @Override public Map toMap(String sql, Class mapKeyType, Class componentType, final Object... bindObjects) throws SQLException { return super.toMap(getPreparedStatement(sql), mapKeyType, componentType, bindObjects); } @Override public , C> Map toMapList(String sql, Class mapKeyType, Class componentType, final Object... bindObjects) throws SQLException { return super.toMapList(getPreparedStatement(sql), mapKeyType, componentType, bindObjects); } @Override public , E extends Map, V> T toCollectionMap(String sql, final Class collectionType, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toCollectionMap(getPreparedStatement(sql), collectionType, componentType, mapValType, bindObjects); } @Override public , E extends Map, V> T toCollectionMap(String sql, T list, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toCollectionMap(getPreparedStatement(sql), list, componentType, mapValType, bindObjects); } @Override public , K, E extends Map, V> T toMapMap(String sql, final Class returnType, Class mapKeyType, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapMap(getPreparedStatement(sql), returnType, mapKeyType, componentType, mapValType, bindObjects); } @Override public , K, E extends Map, V> T toMapMap(String sql, T map, Class mapKeyType, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapMap(getPreparedStatement(sql), map, mapKeyType, componentType, mapValType, bindObjects); } @Override public , K, C extends Collection, E extends Map, V> T toMapCollectionMap(String sql, final Class returnType, Class mapKeyType, Class collectionType, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapCollectionMap(getPreparedStatement(sql), returnType, mapKeyType, collectionType, componentType, mapValType, bindObjects); } @Override public , K, C extends Collection, E extends Map, V> T toMapCollectionMap(String sql, T map, Class mapKeyType, Class collectionType, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapCollectionMap(getPreparedStatement(sql), map, mapKeyType, collectionType, componentType, mapValType, bindObjects); } @Override public , V> ListIterator> toListIteratorMap(String sql, final Class type, Class mapValType, final Object... bindObjects) throws SQLException { return super.toListIteratorMap(getPreparedStatement(sql), type, mapValType, bindObjects); } @Override public , V> Iterator> toIteratorMap(String sql, final Class type, Class mapValType, final Object... bindObjects) throws SQLException { return super.toIteratorMap(getPreparedStatement(sql), type, mapValType, bindObjects); } @Override public , V> Map[] toArrayMap(String sql, final Class type, Class mapValType, final Object... bindObjects) throws SQLException { return super.toArrayMap(getPreparedStatement(sql), type, mapValType, bindObjects); } @Override public , V> List> toListMap(String sql, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toListMap(getPreparedStatement(sql), componentType, mapValType, bindObjects); } @Override public , V> Map> toMapMap(String sql, Class mapKeyType, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapMap(getPreparedStatement(sql), mapKeyType, componentType, mapValType, bindObjects); } @Override public , V> Map>> toMapListMap(String sql, Class mapKeyType, Class componentType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapListMap(getPreparedStatement(sql), mapKeyType, componentType, mapValType, bindObjects); } @Override public ListIterator> toListIteratorMap(String sql, Class mapValType, final Object... bindObjects) throws SQLException { return super.toListIteratorMap(getPreparedStatement(sql), mapValType, bindObjects); } @Override public Iterator> toIteratorMap(String sql, Class mapValType, final Object... bindObjects) throws SQLException { return super.toIteratorMap(getPreparedStatement(sql), mapValType, bindObjects); } @Override public List> toListMap(String sql, Class mapValType, final Object... bindObjects) throws SQLException { return super.toListMap(getPreparedStatement(sql), mapValType, bindObjects); } @Override public Map> toMapMap(String sql, Class mapKeyType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapMap(getPreparedStatement(sql), mapKeyType, mapValType, bindObjects); } @Override public Map>> toMapListMap(String sql, Class mapKeyType, Class mapValType, final Object... bindObjects) throws SQLException { return super.toMapListMap(getPreparedStatement(sql), mapKeyType, mapValType, bindObjects); } }