Caching is the go-to solution in applications to avoid repeating expensive computation and instead prefer some value that can be readily fetched in-memory. A simple caching strategy is to use a cache as a thin layer above database read access as follows:
package main
import "sync"
type Database struct {
cache map[string][]byte
lock sync.RWMutex
}
func (db *Database) GetItem(key []byte) ([]byte, error) {
db.lock.RLock()
if value, ok := db.cache[string(key)]; ok {
db.lock.RUnlock()
return value
}
db.lock.RUnlock()
return db.readFromDatabase(key)
}
func (db *Database) WriteItem(key, value []byte) error {
if err := db.writeToDatabase(key, value); err != nil {
return err
}
db.lock.Lock()
db.cache[string(key)] = value
db.lock.Unlock()
return nil
}
This strategy works great for applications where you have requests to read access for a certain value repeatedly, preventing you from performing a potentially expensive db query and leveraging fast access in-memory. Caching is very helpful. For some problems, however, a cache is definitely not enough.