diff --git a/src/javax/persistence/Cacheable.java b/src/javax/persistence/Cacheable.java
index 9cbd2a749..b52d17ed4 100644
--- a/src/javax/persistence/Cacheable.java
+++ b/src/javax/persistence/Cacheable.java
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/** *****************************************************************************
* Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved.
*
* 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.0
*
- ******************************************************************************/
+ ***************************************************************************** */
package javax.persistence;
import static java.lang.annotation.ElementType.TYPE;
@@ -27,19 +27,28 @@ import java.lang.annotation.Target;
* The value of the Cacheable annotation is inherited by
* subclasses; it can be overridden by specifying
* Cacheable on a subclass.
- *
- *
Cacheable(false) means that the entity and its state must
+ *
+ *
+ * Cacheable(false) means that the entity and its state must
* not be cached by the provider.
- *
+ *
* @since Java Persistence 2.0
*/
-@Target( { TYPE })
+@Target({TYPE})
@Retention(RUNTIME)
public @interface Cacheable {
/**
* (Optional) Whether or not the entity should be cached.
+ *
* @return boolean
*/
boolean value() default true;
+
+ /**
+ * (Optional) 定时自动更新缓存的周期秒数,为0表示不做定时更新, 大于0表示每经过interval秒后会自动从数据库中拉取数据更新Cache
+ *
+ * @return
+ */
+ int interval() default 0;
}
diff --git a/src/org/redkale/source/DistributeTableStrategy.java b/src/org/redkale/source/DistributeTableStrategy.java
index fa23546b2..4d83937a9 100644
--- a/src/org/redkale/source/DistributeTableStrategy.java
+++ b/src/org/redkale/source/DistributeTableStrategy.java
@@ -8,6 +8,7 @@ package org.redkale.source;
import java.io.Serializable;
/**
+ * 不能与Cacheable同时使用
*
*
* 详情见: https://redkale.org
diff --git a/src/org/redkale/source/EntityCache.java b/src/org/redkale/source/EntityCache.java
index a85b1e77f..f34e82ac8 100644
--- a/src/org/redkale/source/EntityCache.java
+++ b/src/org/redkale/source/EntityCache.java
@@ -29,10 +29,10 @@ public final class EntityCache {
private static final Logger logger = Logger.getLogger(EntityCache.class.getName());
- private final ConcurrentHashMap map = new ConcurrentHashMap();
+ private ConcurrentHashMap map = new ConcurrentHashMap();
// CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢;10w数据查询需要 0.062秒, 查询慢40%;
- private final Collection list = new ConcurrentLinkedQueue();
+ private Collection list = new ConcurrentLinkedQueue();
private final Map> sortComparators = new ConcurrentHashMap<>();
@@ -52,8 +52,13 @@ public final class EntityCache {
final EntityInfo info;
- public EntityCache(final EntityInfo info) {
+ final int interval;
+
+ private ScheduledThreadPoolExecutor scheduler;
+
+ public EntityCache(final EntityInfo info, final Cacheable c) {
this.info = info;
+ this.interval = c == null ? 0 : c.interval();
this.type = info.getType();
this.creator = info.getCreator();
this.primary = info.primary;
@@ -80,15 +85,35 @@ public final class EntityCache {
public void fullLoad() {
if (info.fullloader == null) return;
- clear();
+ this.fullloaded = false;
+ ConcurrentHashMap newmap = new ConcurrentHashMap();
List all = info.fullloader.apply(info.source, type);
if (all != null) {
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;
+ 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 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 getType() {
@@ -97,8 +122,12 @@ public final class EntityCache {
public void clear() {
this.fullloaded = false;
- this.list.clear();
- this.map.clear();
+ this.list = new ConcurrentLinkedQueue();
+ this.map = new ConcurrentHashMap();
+ if (this.scheduler != null) {
+ this.scheduler.shutdownNow();
+ this.scheduler = null;
+ }
}
public boolean isFullLoaded() {
diff --git a/src/org/redkale/source/EntityInfo.java b/src/org/redkale/source/EntityInfo.java
index c7c007b3a..96ec02dfc 100644
--- a/src/org/redkale/source/EntityInfo.java
+++ b/src/org/redkale/source/EntityInfo.java
@@ -249,7 +249,7 @@ public final class EntityInfo {
//----------------cache--------------
Cacheable c = type.getAnnotation(Cacheable.class);
if (this.table == null || (!cacheForbidden && c != null && c.value())) {
- this.cache = new EntityCache<>(this);
+ this.cache = new EntityCache<>(this, c);
} else {
this.cache = null;
}
diff --git a/test/org/redkale/test/source/CacheTestBean.java b/test/org/redkale/test/source/CacheTestBean.java
index 142510d44..f32c09ab2 100644
--- a/test/org/redkale/test/source/CacheTestBean.java
+++ b/test/org/redkale/test/source/CacheTestBean.java
@@ -38,9 +38,9 @@ public class CacheTestBean {
BiFunction fullloader = (s, z) -> list;
Method method = EntityInfo.class.getDeclaredMethod("load", Class.class, int.class, boolean.class, Properties.class,
DataSource.class, BiFunction.class);
- method.setAccessible(true);
+ method.setAccessible(true);
final EntityInfo info = (EntityInfo) method.invoke(null, CacheTestBean.class, 0, true, new Properties(), null, fullloader);
- EntityCache cache = new EntityCache(info);
+ EntityCache cache = new EntityCache(info, null);
cache.fullLoad();
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.MAX, "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.IGNORECASEEQUAL, "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.querySheet(null, null, FilterNode.create("name", FilterExpress.IGNORECASENOTLIKE, "B")));
}
@@ -90,7 +90,7 @@ public class CacheTestBean {
@Override
public String toString() {
- return JsonConvert.root().convertTo(this);
+ return JsonConvert.root().convertTo(this);
}
}