Some things never change, even in your database. There are always tables holding geographical data, historical transactions, and mundane status codes that won’t ever be modified for the lifetime of the application. Typically, the data is read from the table at startup and stored in-memory:
public class States{
private List<StatesTbl> stateList = null;
public States(){
stateList = database.fetchStatesList(); //Fetch a list of the US States
}
public List<StatesTbl> getStates(){ //getter for states list
return stateList;
}
}
Other tables are either far too big or complex to cache, so a database fetch is done for each lookup.
How about tables in between? Things like product codes, business addresses, and telephone numbers don’t change often, so it’s efficient to store them in memory in application startup. When they do change, you want to refresh the memory cache without restarting the application, yet not have the overhead of checking the database each time to see if it’s been updated.
One way to do this is to take advantage of Java’s ReentrantReadWriteLocks.
static private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); static private Lock readlock = readWriteLock.readLock(); static private Lock writelock = readWriteLock.writeLock();
Reentrant locks are similar in concept to the Java “synchronize” locks, but with these useful refinements:
- Read locks can occur concurrently, instead of one at a time.
- Write locks wait until read locks have been released.
So ReentrantReadWriteLocks fit our needs very nicely: controlling access to an object that is read far more often than it’s written to.
An implementation of our modified data cache:
public List<CompanyProductCodesTbl> getCodes(){
readlock.lock();
try{
return company_codes_list;
}finally{
readlock.unlock();
}
}
public void refreshCodes(){
writelock.lock();
try{
company_codes_list=database.getCompanyCodes();
}finally{
writelock.unlock();
}
}
Wrapping the locks around try/finally blocks ensures that locks will always be released in the event that an exception occurs.
How does “refreshCodes()” get executed? In this case it is a manual process. When the database is refreshed for that particular table, care is needed to execute refreshCodes(). Since updates are rare, there could be an administrative console or a data process that triggers this function at the same event the Product Codes table is updated.
This saves an enormous amount of overhead in making sure your seldom changed data is always current in your running application.