diff --git a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingResultSetMapper.java b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingResultSetMapper.java index 792547d..e8aa30a 100644 --- a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingResultSetMapper.java +++ b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingResultSetMapper.java @@ -2,9 +2,13 @@ package com.moparisthebest.jdbc; import java.sql.ResultSet; import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; public class CachingResultSetMapper extends ResultSetMapper { + protected final Map cache = new HashMap(); + public CachingResultSetMapper(Calendar cal, int arrayMaxLength) { super(cal, arrayMaxLength); } @@ -15,6 +19,6 @@ public class CachingResultSetMapper extends ResultSetMapper { @Override protected RowToObjectMapper getRowMapper(ResultSet resultSet, Class returnTypeClass, Calendar cal, Class mapValType) { - return new CachingRowToObjectMapper(resultSet, returnTypeClass, cal, mapValType); + return new CachingRowToObjectMapper(cache, resultSet, returnTypeClass, cal, mapValType); } } diff --git a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingRowToObjectMapper.java b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingRowToObjectMapper.java index 0f9c27a..6d2f4ee 100644 --- a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingRowToObjectMapper.java +++ b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CachingRowToObjectMapper.java @@ -5,22 +5,19 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.Calendar; -import java.util.HashMap; import java.util.Map; public class CachingRowToObjectMapper extends RowToObjectMapper { - protected static final Map cache = new HashMap(); + protected final Map cache; + protected final ResultSetKey keys; - protected final int thisHash; - protected final String[] keys; - - public CachingRowToObjectMapper(ResultSet resultSet, Class returnTypeClass, Calendar cal, Class mapValType) { + public CachingRowToObjectMapper(final Map cache, ResultSet resultSet, Class returnTypeClass, Calendar cal, Class mapValType) { super(resultSet, returnTypeClass, cal, mapValType); + this.cache = cache; try { - keys = super.getKeysFromResultSet(); - //System.out.printf("keys: %d, %s: %d\n", Arrays.hashCode(keys), _returnTypeClass, _returnTypeClass.hashCode()); - thisHash = Arrays.hashCode(keys) ^ _returnTypeClass.hashCode(); + keys = new ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass); + //System.out.printf("keys: %s\n", keys); } catch (SQLException e) { throw new MapperException("CachingRowToObjectMapper: SQLException: " + e.getMessage(), e); } @@ -28,32 +25,61 @@ public class CachingRowToObjectMapper extends RowToObjectMapper { @Override protected String[] getKeysFromResultSet() throws SQLException { - return keys; + return keys.keys; } @Override protected void getFieldMappings() throws SQLException { - FieldMapping fm = cache.get(thisHash); + FieldMapping fm = cache.get(keys); if (fm == null) { - //System.out.printf("cache miss, hashcode: %d\n", thisHash); + //System.out.printf("cache miss, keys: %s\n", keys); // generate and put into cache super.getFieldMappings(); - synchronized (cache) { - // I *think* we only need to synchronize here, instead of around the get as well - // it may allow some leaks (field mappings being generated more than once) - // but the performance benefits of not having this entire method synchronized - // statically probably outweighs the negatives - cache.put(thisHash, new FieldMapping(_fields, _fieldTypes)); - } + cache.put(keys, new FieldMapping(_fields, _fieldTypes)); } else { - //System.out.printf("cache hit, hashcode: %d\n", thisHash); + //System.out.printf("cache hit, keys: %s\n", keys); // load from cache _fields = fm._fields; _fieldTypes = fm._fieldTypes; } } - private static class FieldMapping { + static class ResultSetKey { + protected final String[] keys; + protected final Class returnTypeClass; + + public ResultSetKey(final String[] keys, final Class returnTypeClass) { + this.keys = keys; + this.returnTypeClass = returnTypeClass; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof ResultSetKey)) return false; + + final ResultSetKey that = (ResultSetKey) o; + + return Arrays.equals(keys, that.keys) && (returnTypeClass != null ? returnTypeClass.equals(that.returnTypeClass) : that.returnTypeClass == null); + } + + @Override + public int hashCode() { + int result = Arrays.hashCode(keys); + result = 31 * result + (returnTypeClass != null ? returnTypeClass.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "ResultSetKey{" + + "keys=" + Arrays.toString(keys) + + ", returnTypeClass=" + returnTypeClass + + '}'; + } + } + + static class FieldMapping { public final AccessibleObject[] _fields; public final int[] _fieldTypes;