Skip to content
KwonNam Son edited this page Nov 21, 2015 · 28 revisions

hibernate4-memcached getting started

This page is about hibernate4-memcached implementation - Hibernate4MemcachedRegionFactory with spymemcached adapter which uses KryoTranscoder.

You can make and use your own MemcachedAdapter and Transcoder.

  • Currently supported concurrency strategies are READ_ONLY, NONSTRICT_READ_WRITE.
  • Memcached does not have region(namespace) concept but this cache implementation supports region conecpt. Refer to Memcached Namespacing
  • When entity classes are changed, hibernate4-memcached checks serialVersionUID of those classes and if the serialVersionUIDs are different, it ignores cached data quietly. So you must change serialVersionUID when class's fields are changed or just let JVM change the serialVersionUID.

Refer to Home for maven/gradle dependencies.

JPA/Hibernate properties

hibernate properties

hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
hibernate.cache.default_cache_concurrency_strategy=NONSTRICT_READ_WRITE
hibernate.cache.region.factory_class=kr.pe.kwonnam.hibernate4memcached.Hibernate4MemcachedRegionFactory
hibernate.cache.region_prefix=[Cache Region Prefix]
hibernate.cache.provider_configuration_file_resource_path=META-INF/h4m-properties.xml
hibernate.cache.use_structured_entries=false
  • hibernate.cache.default_cache_concurrency_strategy : currently only READ_ONLY, NONSTRICT_READ_WRITE supported
  • hibernate.cache.provider_configuration_file_resource_path : optional. You can set all properties in JPA EntityManagerFactory properties(including persistence.xml) or SessionFactory properties or the file indicated by this property. The file must be in classpath. The property value must NOT start with /.

Hibernate4MemcachedRegionFactory properties

h4m.adapter.class=kr.pe.kwonnam.hibernate4memcached.spymemcached.SpyMemcachedAdapter

SpyMemcachedAdapter Properties

h4m.adapter.spymemcached.hosts=localhost:11211,yourhost:11211
h4m.adapter.spymemcached.hashalgorithm=KETAMA_HASH
h4m.adapter.spymemcached.operation.timeout.millis=5000
h4m.adapter.spymemcached.transcoder=kr.pe.kwonnam.hibernate4memcached.spymemcached.KryoTranscoder
h4m.adapter.spymemcached.cachekey.prefix=h4m
h4m.adapter.spymemcached.kryotranscoder.compression.threashold.bytes=20000
  • h4m.adapter.spymemcached.hashalgorithm : net.spy.memcached.DefaultHashAlgorithm enum value.
  • h4m.adapter.spymemcached.cachekey.prefix : optional. memcached cache key prefix.(for when you use one memcached server for many kind caches, it will help you not to conflict each caches.
  • h4m.adapter.spymemcached.kryotranscoder.compression.threashold.bytes : KryoTranscoder compress data with lz4 when the size of data is over this property value. If you set this value too small, it's just wasting CPU.

Cache region expiry seconds properties

h4m.expiry.seconds=600 # 10 minutes
h4m.expiry.seconds.[CacheRegionPrefix].org.hibernate.cache.spi.UpdateTimestampsCache=86400 # a day
h4m.expiry.seconds.[CacheRegionPrefix].org.hibernate.cache.internal.StandardQueryCache=3600 # 1 hour

h4m.expiry.seconds.[CacheRegionPrefix].[region]=1800 # 30 minutes
  • h4m.expiry.seconds : default expiry seconds for all cache regions.
  • h4m.expiry.seconds.[CacheRegionPrefix].org.hibernate.cache.spi.UpdateTimestampsCache : for UpdateTimestampsCache
  • h4m.expiry.seconds.[CacheRegionPrefix].org.hibernate.cache.internal.StandardQueryCache : for default query cache
  • h4m.expiry.seconds.[CacheRegionPrefix].[region] : for your own regions.

Entity Cache

@org.hibernate.annotations.Cache(region = "[region]", usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public Class YourEntity implements Serializable {
	@OneToMany(fetch = FetchType.LAZY)
	@JoinColumn(name = "parentId")
	@org.hibernate.annotations.Cache(region = "[region]" usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
	private List<Child> children;
}
  • MUST implement Serializable
  • I recommend NOT specify serialVersionUID. I think it's better to let JVM generate servialVersionUID.

Query Cache

  • org.hibernate.cacheable=true
  • org.hibernate.cacheRegion=[query cache region] : optionial. If missed, org.hibernate.cache.internal.StandardQueryCache is used.
  • Hibernate generate very long cache key for query. SpyMemcachedAdapter hashes the key with MD5 and hashCode() to shorten the key.

Named Query

@Entity
@Table(name = "books")
@NamedQuery(name = "Book.byEdition",
		query = "from Book where edition=:edition",
		hints = {
				@QueryHint(name = "org.hibernate.cacheable", value = "true"),
				@QueryHint(name = "org.hibernate.cacheRegion", value = "book-by-named-edition")
		}
)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "books")
public class Book implements Serializable {

Spring Data JPA

@QueryHints({@QueryHint(name = "org.hibernate.cacheable", value = "true") })
List<YourEntity> findBySomething(Param yourparam);

Caution

  • Region name and cache key prefix are used for memcached key. So you have to set the values which can be used as memcached key.
  • I recommend not specifying serialVersionUID.
  • Beware of memcached limitations.
  • Key bytes max size : 250 bytes
  • Max expiry seconds : 30 days(2592000 seconds)

References