mirror of
https://github.com/moparisthebest/JdbcMapper
synced 2024-11-25 10:22:17 -05:00
Make CachingResultSetMapper not have an entire cache shared over the whole application, only per instance, also fix hashing logic
This commit is contained in:
parent
1b2f248574
commit
9d131e13ce
@ -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<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping> cache = new HashMap<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping>();
|
||||
|
||||
public CachingResultSetMapper(Calendar cal, int arrayMaxLength) {
|
||||
super(cal, arrayMaxLength);
|
||||
}
|
||||
@ -15,6 +19,6 @@ public class CachingResultSetMapper extends ResultSetMapper {
|
||||
|
||||
@Override
|
||||
protected <T> RowToObjectMapper<T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
return new CachingRowToObjectMapper<T>(resultSet, returnTypeClass, cal, mapValType);
|
||||
return new CachingRowToObjectMapper<T>(cache, resultSet, returnTypeClass, cal, mapValType);
|
||||
}
|
||||
}
|
||||
|
@ -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<T> extends RowToObjectMapper<T> {
|
||||
|
||||
protected static final Map<Integer, FieldMapping> cache = new HashMap<Integer, FieldMapping>();
|
||||
protected final Map<ResultSetKey, FieldMapping> cache;
|
||||
protected final ResultSetKey keys;
|
||||
|
||||
protected final int thisHash;
|
||||
protected final String[] keys;
|
||||
|
||||
public CachingRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
public CachingRowToObjectMapper(final Map<ResultSetKey, FieldMapping> cache, ResultSet resultSet, Class<T> 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<T> extends RowToObjectMapper<T> {
|
||||
|
||||
@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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user