@Cacheable增加定时更新缓存功能
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
/*******************************************************************************
|
/** *****************************************************************************
|
||||||
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
|
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
* Linda DeMichiel - Java Persistence 2.1
|
* Linda DeMichiel - Java Persistence 2.1
|
||||||
* Linda DeMichiel - Java Persistence 2.0
|
* Linda DeMichiel - Java Persistence 2.0
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
***************************************************************************** */
|
||||||
package javax.persistence;
|
package javax.persistence;
|
||||||
|
|
||||||
import static java.lang.annotation.ElementType.TYPE;
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
@@ -27,19 +27,28 @@ import java.lang.annotation.Target;
|
|||||||
* The value of the <code>Cacheable</code> annotation is inherited by
|
* The value of the <code>Cacheable</code> annotation is inherited by
|
||||||
* subclasses; it can be overridden by specifying
|
* subclasses; it can be overridden by specifying
|
||||||
* <code>Cacheable</code> on a subclass.
|
* <code>Cacheable</code> on a subclass.
|
||||||
*
|
*
|
||||||
* <p> <code>Cacheable(false)</code> means that the entity and its state must
|
* <p>
|
||||||
|
* <code>Cacheable(false)</code> means that the entity and its state must
|
||||||
* not be cached by the provider.
|
* not be cached by the provider.
|
||||||
*
|
*
|
||||||
* @since Java Persistence 2.0
|
* @since Java Persistence 2.0
|
||||||
*/
|
*/
|
||||||
@Target( { TYPE })
|
@Target({TYPE})
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface Cacheable {
|
public @interface Cacheable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Optional) Whether or not the entity should be cached.
|
* (Optional) Whether or not the entity should be cached.
|
||||||
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
boolean value() default true;
|
boolean value() default true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Optional) 定时自动更新缓存的周期秒数,为0表示不做定时更新, 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int interval() default 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.redkale.source;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 不能与Cacheable同时使用
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* 详情见: https://redkale.org
|
* 详情见: https://redkale.org
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ public final class EntityCache<T> {
|
|||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(EntityCache.class.getName());
|
private static final Logger logger = Logger.getLogger(EntityCache.class.getName());
|
||||||
|
|
||||||
private final ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap();
|
private ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap();
|
||||||
|
|
||||||
// CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢;10w数据查询需要 0.062秒, 查询慢40%;
|
// CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢;10w数据查询需要 0.062秒, 查询慢40%;
|
||||||
private final Collection<T> list = new ConcurrentLinkedQueue();
|
private Collection<T> list = new ConcurrentLinkedQueue();
|
||||||
|
|
||||||
private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>();
|
private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@@ -52,8 +52,13 @@ public final class EntityCache<T> {
|
|||||||
|
|
||||||
final EntityInfo<T> info;
|
final EntityInfo<T> info;
|
||||||
|
|
||||||
public EntityCache(final EntityInfo<T> info) {
|
final int interval;
|
||||||
|
|
||||||
|
private ScheduledThreadPoolExecutor scheduler;
|
||||||
|
|
||||||
|
public EntityCache(final EntityInfo<T> info, final Cacheable c) {
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
this.interval = c == null ? 0 : c.interval();
|
||||||
this.type = info.getType();
|
this.type = info.getType();
|
||||||
this.creator = info.getCreator();
|
this.creator = info.getCreator();
|
||||||
this.primary = info.primary;
|
this.primary = info.primary;
|
||||||
@@ -80,15 +85,35 @@ public final class EntityCache<T> {
|
|||||||
|
|
||||||
public void fullLoad() {
|
public void fullLoad() {
|
||||||
if (info.fullloader == null) return;
|
if (info.fullloader == null) return;
|
||||||
clear();
|
this.fullloaded = false;
|
||||||
|
ConcurrentHashMap newmap = new ConcurrentHashMap();
|
||||||
List<T> all = info.fullloader.apply(info.source, type);
|
List<T> all = info.fullloader.apply(info.source, type);
|
||||||
if (all != null) {
|
if (all != null) {
|
||||||
all.stream().filter(x -> x != null).forEach(x -> {
|
all.stream().filter(x -> x != null).forEach(x -> {
|
||||||
this.map.put(this.primary.get(x), x);
|
newmap.put(this.primary.get(x), x);
|
||||||
});
|
});
|
||||||
this.list.addAll(all);
|
|
||||||
}
|
}
|
||||||
|
this.list = all == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all);
|
||||||
|
this.map = newmap;
|
||||||
this.fullloaded = true;
|
this.fullloaded = true;
|
||||||
|
if (this.interval > 0) {
|
||||||
|
this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
|
||||||
|
final Thread t = new Thread(r, "EntityCache-" + type + "-Thread");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
this.scheduler.scheduleAtFixedRate(() -> {
|
||||||
|
ConcurrentHashMap newmap2 = new ConcurrentHashMap();
|
||||||
|
List<T> all2 = info.fullloader.apply(info.source, type);
|
||||||
|
if (all2 != null) {
|
||||||
|
all2.stream().filter(x -> x != null).forEach(x -> {
|
||||||
|
newmap2.put(this.primary.get(x), x);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.list = all2 == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all2);
|
||||||
|
this.map = newmap2;
|
||||||
|
}, interval - System.currentTimeMillis() / 1000 % interval, interval, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<T> getType() {
|
public Class<T> getType() {
|
||||||
@@ -97,8 +122,12 @@ public final class EntityCache<T> {
|
|||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
this.fullloaded = false;
|
this.fullloaded = false;
|
||||||
this.list.clear();
|
this.list = new ConcurrentLinkedQueue();
|
||||||
this.map.clear();
|
this.map = new ConcurrentHashMap();
|
||||||
|
if (this.scheduler != null) {
|
||||||
|
this.scheduler.shutdownNow();
|
||||||
|
this.scheduler = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFullLoaded() {
|
public boolean isFullLoaded() {
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ public final class EntityInfo<T> {
|
|||||||
//----------------cache--------------
|
//----------------cache--------------
|
||||||
Cacheable c = type.getAnnotation(Cacheable.class);
|
Cacheable c = type.getAnnotation(Cacheable.class);
|
||||||
if (this.table == null || (!cacheForbidden && c != null && c.value())) {
|
if (this.table == null || (!cacheForbidden && c != null && c.value())) {
|
||||||
this.cache = new EntityCache<>(this);
|
this.cache = new EntityCache<>(this, c);
|
||||||
} else {
|
} else {
|
||||||
this.cache = null;
|
this.cache = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ public class CacheTestBean {
|
|||||||
BiFunction<DataSource, Class, List> fullloader = (s, z) -> list;
|
BiFunction<DataSource, Class, List> fullloader = (s, z) -> list;
|
||||||
Method method = EntityInfo.class.getDeclaredMethod("load", Class.class, int.class, boolean.class, Properties.class,
|
Method method = EntityInfo.class.getDeclaredMethod("load", Class.class, int.class, boolean.class, Properties.class,
|
||||||
DataSource.class, BiFunction.class);
|
DataSource.class, BiFunction.class);
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
final EntityInfo<CacheTestBean> info = (EntityInfo<CacheTestBean>) method.invoke(null, CacheTestBean.class, 0, true, new Properties(), null, fullloader);
|
final EntityInfo<CacheTestBean> info = (EntityInfo<CacheTestBean>) method.invoke(null, CacheTestBean.class, 0, true, new Properties(), null, fullloader);
|
||||||
EntityCache<CacheTestBean> cache = new EntityCache(info);
|
EntityCache<CacheTestBean> cache = new EntityCache(info, null);
|
||||||
cache.fullLoad();
|
cache.fullLoad();
|
||||||
|
|
||||||
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.COUNT, "name", null));
|
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.COUNT, "name", null));
|
||||||
@@ -49,9 +49,9 @@ public class CacheTestBean {
|
|||||||
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.SUM, "price", null));
|
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.SUM, "price", null));
|
||||||
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MAX, "price", null));
|
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MAX, "price", null));
|
||||||
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MIN, "price", null));
|
System.out.println(cache.queryColumnMap("pkgid", FilterFunc.MIN, "price", null));
|
||||||
|
|
||||||
System.out.println(cache.find(null, FilterNode.create("name", FilterExpress.EQUAL, "BB")));
|
System.out.println(cache.find(null, FilterNode.create("name", FilterExpress.EQUAL, "BB")));
|
||||||
System.out.println(cache.find(null, FilterNode.create("name", FilterExpress.IGNORECASEEQUAL, "BB")));
|
System.out.println(cache.find(null, FilterNode.create("name", FilterExpress.IGNORECASEEQUAL, "BB")));
|
||||||
System.out.println(cache.querySheet(null, null, FilterNode.create("name", FilterExpress.IGNORECASENOTLIKE, "B")));
|
System.out.println(cache.querySheet(null, null, FilterNode.create("name", FilterExpress.IGNORECASENOTLIKE, "B")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ public class CacheTestBean {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return JsonConvert.root().convertTo(this);
|
return JsonConvert.root().convertTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user