001// ______________________________________________________ 002// Generated by sql2java - https://github.com/10km/sql2java-2-6-7 (custom branch) 003// modified by guyadong from 004// sql2java original version https://sourceforge.net/projects/sql2java/ 005// JDBC driver used at code generation time: com.mysql.jdbc.Driver 006// template: base.table.loadcaching.java.vm 007// ______________________________________________________ 008package net.gdface.facelog.db; 009 010import java.util.concurrent.ConcurrentMap; 011import java.util.concurrent.ExecutionException; 012import java.util.concurrent.TimeUnit; 013 014import com.google.common.cache.CacheBuilder; 015import com.google.common.cache.CacheLoader; 016import com.google.common.cache.LoadingCache; 017import com.google.common.util.concurrent.UncheckedExecutionException; 018 019import net.gdface.facelog.db.exception.ObjectRetrievalException; 020 021/** 022 * 023 * 基于 {@link LoadingCache}实现表数据缓存,并可以通过{@link TableListener}实现缓存数据自动更新 024 * @author guyadong 025 * 026 * @param <K> 主键类型(Primary or Unique) 027 * @param <B> 数据库记录对象类型(Java Bean) 028 */ 029public abstract class BaseTableLoadCaching<K ,B extends BaseBean<B>> implements ITableCache<K, B> { 030 private final LoadingCache<K, B> cache; 031 protected final ConcurrentMap<K, B> cacheMap; 032 protected final TableListener.Adapter<B> tableListener; 033 /** 当前更新策略 */ 034 private final UpdateStrategy updateStrategy; 035 /** 036 * 返回bean中主键值 037 * @param bean input record bean 038 * @return K value 039 */ 040 protected abstract K returnKey(B bean); 041 /** 042 * 从数据库中加载主键(pk)指定的记录 043 * @param key primary key 044 * @return B bean 045 * @throws Exception 046 */ 047 protected abstract B loadfromDatabase(K key)throws Exception; 048 049 public BaseTableLoadCaching(){ 050 this(DEFAULT_CACHE_MAXIMUMSIZE, 051 DEFAULT_DURATION, 052 DEFAULT_TIME_UNIT); 053 } 054 public BaseTableLoadCaching(long maximumSize){ 055 this(maximumSize, 056 DEFAULT_DURATION, 057 DEFAULT_TIME_UNIT); 058 } 059 public BaseTableLoadCaching(long maximumSize,long durationMinutes){ 060 this(maximumSize,durationMinutes,DEFAULT_TIME_UNIT); 061 } 062 public BaseTableLoadCaching(long maximumSize,long duration, TimeUnit unit) { 063 this(DEFAULT_STRATEGY,maximumSize,duration,unit); 064 } 065 /** 066 * 构造函数 067 * @param updateStrategy 缓存更新策略 068 * @param maximumSize 最大缓存容量,参见 {@link CacheBuilder#maximumSize(long)} 069 * @param duration 失效时间,参见 {@link CacheBuilder#expireAfterWrite(long, TimeUnit)} 070 * @param unit {@code duration}的时间单位 071 */ 072 public BaseTableLoadCaching(UpdateStrategy updateStrategy,long maximumSize,long duration, TimeUnit unit) { 073 if(null == updateStrategy ){ 074 updateStrategy = DEFAULT_STRATEGY; 075 } 076 if(0 >= maximumSize){ 077 maximumSize = DEFAULT_CACHE_MAXIMUMSIZE; 078 } 079 if(0 >= duration){ 080 maximumSize = DEFAULT_DURATION; 081 } 082 if(null == unit){ 083 unit = DEFAULT_TIME_UNIT; 084 } 085 this.updateStrategy = updateStrategy; 086 cache = CacheBuilder.newBuilder() 087 .maximumSize(maximumSize) 088 .expireAfterWrite(duration, unit) 089 .build( 090 new CacheLoader<K,B>() { 091 @Override 092 public B load(K key) throws Exception { 093 return loadfromDatabase(key); 094 }}); 095 cacheMap = cache.asMap(); 096 // 初始化侦听器,当表数据改变时自动更新缓存 097 tableListener = new TableListener.Adapter<B>(){ 098 @Override 099 public void afterUpdate(B bean) { 100 update(bean); 101 } 102 103 @Override 104 public void afterInsert(B bean) { 105 update(bean); 106 } 107 108 @Override 109 public void afterDelete(B bean) { 110 // the remove method allow null key 111 // see also com.google.common.cache.LocalCache.remove(Object key) 112 cacheMap.remove(returnKey(bean)); 113 }}; 114 } 115 /** 116 * @see com.google.common.cache.LoadingCache#get(Object) 117 */ 118 @Override 119 public B getBean(K key)throws ExecutionException{ 120 return cache.get(key); 121 } 122 /** 123 * @see com.google.common.cache.LoadingCache#getIfPresent(Object) 124 */ 125 @Override 126 public B getBeanIfPresent(K key){ 127 return null == key ? null : cache.getIfPresent(key); 128 } 129 /** 130 * @see com.google.common.cache.LoadingCache#getUnchecked(Object) 131 */ 132 @Override 133 public B getBeanUnchecked(K key){ 134 try{ 135 return cache.getUnchecked(key); 136 }catch(UncheckedExecutionException e){ 137 if(e.getCause() instanceof ObjectRetrievalException){ 138 return null; 139 } 140 throw e; 141 } 142 } 143 @Override 144 public void remove(B bean){ 145 cacheMap.remove(returnKey(bean)); 146 } 147 /** 148 * 根据当前更新策略({@link UpdateStrategy})将{@code bean}更新到缓存 149 * @see ITableCache#update(net.gdface.facelog.db.BaseBean) 150 */ 151 @Override 152 public void update(B bean){ 153 if(UpdateStrategy.refresh == updateStrategy){ 154 updateStrategy.update(cacheMap, new ReloadEntry(returnKey(bean))); 155 }else{ 156 updateStrategy.update(cacheMap, new ImmutableEntry<K,B>(returnKey(bean),bean)); 157 } 158 } 159 private class ReloadEntry extends ImmutableEntry<K,B>{ 160 public ReloadEntry(K key) { 161 super(key); 162 } 163 164 @Override 165 public B reload()throws Exception { 166 return loadfromDatabase(getKey()); 167 } 168 } 169 public UpdateStrategy getUpdateStrategy() { 170 return updateStrategy; 171 } 172 /** 173 * @return cacheMap 174 */ 175 public ConcurrentMap<K, B> getCacheMap() { 176 return cacheMap; 177 } 178} 179