Reputation: 1727
I would like to put all the data from the following sql in a map( because this sql is called many times and instead of going to db everytime ), but I am wondering how to implement the <= for the timestamp
EDIT:
I am using Oracle, just updated the tags, however, I am using PreparedStatement in java which caches queries, without being recompiled, but our program doesn't have a cache solution to cache the data from the table. going to the db and getting the data is taking 2 ms roundtrip, but getting the data from the HashMap would take a nano second. This query is being executed around 20,000 times and we would like to load all the data initially and put it inside the Hashmap.
END OF EDIT.
SELECT ar
FROM table1
WHERE fk_col1 = ?
AND timestamp_col <= ?
ORDER BY date DESC
The way I did is as follows: but I am not sure, the timestamp_col in equals and hashCode is right. Could you suggest the modifications?
public class Table1Key
{
private String fk_col1;
private java.sql.Timestamp timestamp_col;
//setters and getters here.
//implementing hashCode and equals.
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((fk_col1 == null) ? 0 : fk_col1.hashCode());
result = prime * result
+ ((timestamp_col == null) ? 0 : timestamp_col.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Table1Key other = (Table1Key) obj;
if (fk_col1 == null) {
if (other.fk_col1 != null)
return false;
} else if (!fk_col1.equals(other.fk_col1))
return false;
if (timestamp_col == null) {
if (other.timestamp_col != null)
return false;
} else if (!timestamp_col.equals(other.timestamp_col))
return false;
return true;
}
}
...
private Map<Table1Key, String> map = Functions.getHashMapInstance();
public class Functions {
...
public static <K,V> HashMap<K,V> getHashMapInstance() {
return new HashMap<K,V>();
}
}
So, I would populate the map like the following:
private void populateMap() throws SQLException {
try {
ps = conn.prepareStatement(table1Sql);
ps.setFetchSize(20000);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
Table1Key rdk = new Table1Key();
String ar = rs.getString(1);
rdk.setFk_col1(rs.getString(2));
rdk.setTimestampCol(rs.getTimestamp(3));
if(actualRateMap.get(rdk) == null) {
actualRateMap.put(rdk, ar);
}
}
} catch (SQLException e) {
e.printStackTrace();
throw e;
} finally {
ps.close();
}
}
//set the key here.
Table1Key tk = new Table1Key();
tk.setFk_col1(col1);
tk.setTimestampCol(timestamp);
String ar = actualRateMap.get(tk);
//My main concern here is .. this will work if the sql has timestamp_col = ?, but what if the timestamp_col is < than what is present in the map?
if(actualRate != null) {
Logger.info("Actual Rate:"+actualRate);
}
Upvotes: 2
Views: 1863
Reputation: 32014
HashMap
doesn't do the job for your case, rather TreeMap can help.
a): RangeMap solution
Guava RangeMap is designed to handle such case:
//Initial RangeMap
final RangeMap<java.sql.Timestamp, String> cache = TreeRangeMap.create();
...
String value = cache.get(thisTimestamp);
if(value == null){
String queryFromDB = ...;//Query from DB
cache.put(Range.atMost(thisTimestamp), queryFromDB);
value = queryFromDB;
}
Of course, 'fk_coll' is problem. so you could define Map<String/*fk_coll*/, RangeMap<java.sql.Timestamp, String>>
to handle the case.
b): TreeMap solution
final TreeMap<java.sql.Timestamp, String> cache = new TreeMap<>();
...
//Get least key greater than or equal to the 'thisTimestamp'
Map.Entry<java.sql.Timestamp, String> entry = cache.ceilingEntry(thisTimestamp);
if(entry == null){
String queryFromDB = ...;//Query from DB
cache.put(thisTimestamp, queryFromDB);
value = queryFromDB;
} else {
value = entry.getValue();
}
and
HashMap<String/*fk_coll*/, TreeMap<java.sql.Timestamp, String>>
handles 'fk_coll'.
plus: evict is a problem in any cache case.
Upvotes: 2
Reputation: 1303
While HashMap does not specify the order of elements, TreeMap does. I didn't test the following code, but I guess it should work:
TreeMap<Timestamp, String> map = new TreeMap<Timestamp, String>(new Comparator<Timestamp>() {
public int compare(Timestamp t1, Timestamp t2) {
// Inverse order is required for using tailMap() as <= operator
return t2.compareTo(t1);
}
public boolean equals(Object o) {
throw new UnsupportedOperationException("This operation has not been implemented!");
}
});
// TODO: insert data to the map
// ...
// Get the first key that is <= timestamp (remember that map is using inverse order)
TreeMap<Timestamp, String> tailMap = map.tailMap(timestamp);
Timestamp firstKey = tailMap.firstKey();
if (firstKey != null) {
// Get the value
String value = tailMap.get(firstKey);
}
Upvotes: 0