Skip to content

Commit 34798e8

Browse files
Merge pull request #94 from k-r-g/useAffectedRows
Optionally skip updating methodValueCache/listeners when nothing updated
2 parents 3e21ae6 + bff440a commit 34798e8

File tree

6 files changed

+148
-69
lines changed

6 files changed

+148
-69
lines changed

gemini/src/main/java/com/techempower/cache/CacheGroup.java

+11-8
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public TLongObjectMap<T> map()
241241
* Add an object to the cache and the data store.
242242
*/
243243
@Override
244-
public void put(T object)
244+
public int put(T object)
245245
{
246246
if (readOnly())
247247
{
@@ -255,7 +255,7 @@ public void put(T object)
255255
final boolean persisted = isPersisted(object);
256256

257257
// Persist the object.
258-
putPersistent(object);
258+
int rowsUpdated = putPersistent(object);
259259

260260
if (persisted)
261261
{
@@ -268,6 +268,7 @@ public void put(T object)
268268
// Object was not persisted, so let's add it to the cache.
269269
addToCache(object);
270270
}
271+
return rowsUpdated;
271272
}
272273

273274
/**
@@ -278,18 +279,18 @@ public void put(T object)
278279
* This method is exposed as a protected class to allow subclasses to
279280
* specialize the persistence behavior.
280281
*/
281-
protected void putPersistent(T object)
282+
protected int putPersistent(T object)
282283
{
283284
// Ask the EntityGroup parent to persist the changes.
284-
super.put(object);
285+
return super.put(object);
285286
}
286287

287288
/**
288289
* Add objects to the cache and the data store.
289290
*/
290291
@SuppressWarnings("unchecked")
291292
@Override
292-
public void putAll(Collection<T> objectsToPut)
293+
public int putAll(Collection<T> objectsToPut)
293294
{
294295
if (readOnly())
295296
{
@@ -315,14 +316,16 @@ public void putAll(Collection<T> objectsToPut)
315316
}
316317

317318
// Persist the changes.
318-
putAllPersistent(objectsToPut);
319+
int rowsUpdated = putAllPersistent(objectsToPut);
319320

320321
// Reorder any previously-persisted objects in case the field we are
321322
// ordered by was changed.
322323
reorder(CollectionHelper.toLongArray(persisted));
323324

324325
// Add any objects we did not previously know about.
325326
addToCache(nonPersisted.toArray((T[])Array.newInstance(type(), nonPersisted.size())));
327+
328+
return rowsUpdated;
326329
}
327330

328331
/**
@@ -333,10 +336,10 @@ public void putAll(Collection<T> objectsToPut)
333336
* This method is exposed as a protected class to allow subclasses to
334337
* specialize the persistence behavior.
335338
*/
336-
protected void putAllPersistent(Collection<T> objectsToPut)
339+
protected int putAllPersistent(Collection<T> objectsToPut)
337340
{
338341
// Ask the EntityGroup parent to persist the objects.
339-
super.putAll(objectsToPut);
342+
return super.putAll(objectsToPut);
340343
}
341344

342345
/**

gemini/src/main/java/com/techempower/cache/EntityStore.java

+57-30
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ public class EntityStore
104104
private boolean initialized = false;
105105
private boolean cacheMethodValues = false;
106106

107+
/**
108+
* Whether to expect the return value from Statement.executeUpdate() to indicate
109+
* whether the row was actually changed. If using MySQL and the connect string
110+
* has useAffectedRows=true set on it, then this can be used. It defaults to
111+
* false because it is MySQL-specific and requires explicitly enabling this in
112+
* the connect string.
113+
*/
114+
private boolean useAffectedRows = false;
115+
107116
/**
108117
* The registered method value caches. These allow you to quickly find
109118
* entities by the value of a given field.
@@ -201,6 +210,14 @@ public void configure(EnhancedProperties props)
201210
cacheMethodValues = props.getBoolean("CacheController.CacheMethodValues", false);
202211
cacheMethodValues = props.getBoolean("EntityStore.CacheMethodValues", cacheMethodValues);
203212

213+
// Whether to expect the return value from Statement.executeUpdate() to indicate
214+
// whether the row was actually changed.
215+
useAffectedRows = props.getBoolean("EntityStore.UseAffectedRows", useAffectedRows);
216+
if (useAffectedRows)
217+
{
218+
log.warn("EntityStore.UseAffectedRows is enabled, which REQUIRES that the database connection be configured so update statements return the count of affected rows. If unsure, disable this.");
219+
}
220+
204221
methodValueCaches = new HashMap<>();
205222

206223
// This should only happen when the application is reconfigured.
@@ -1061,20 +1078,25 @@ public <T extends Identifiable> void put(T entity)
10611078
throw new ControllerError("Cannot put null entity.");
10621079
}
10631080

1064-
getGroupSafe((Class<T>)entity.getClass()).put(entity);
1065-
1066-
// Update method value caches.
1067-
final MethodValueCache<?> methodValueCache = methodValueCaches.get(entity.getClass());
1068-
if (methodValueCache != null)
1069-
{
1070-
methodValueCache.update(entity.getId());
1071-
}
1072-
1073-
// Notify the listeners.
1074-
final CacheListener[] toNotify = listeners;
1075-
for (CacheListener listener : toNotify)
1081+
int rowsUpdated = getGroupSafe((Class<T>)entity.getClass()).put(entity);
1082+
1083+
// If useAffectedRows is enabled, then only update the methodValueCache and
1084+
// notify the listeners if an actual change was persisted.
1085+
if (!useAffectedRows || rowsUpdated > 0)
10761086
{
1077-
listener.cacheObjectExpired(entity.getClass(), entity.getId());
1087+
// Update method value caches.
1088+
final MethodValueCache<?> methodValueCache = methodValueCaches.get(entity.getClass());
1089+
if (methodValueCache != null)
1090+
{
1091+
methodValueCache.update(entity.getId());
1092+
}
1093+
1094+
// Notify the listeners.
1095+
final CacheListener[] toNotify = listeners;
1096+
for (CacheListener listener : toNotify)
1097+
{
1098+
listener.cacheObjectExpired(entity.getClass(), entity.getId());
1099+
}
10781100
}
10791101
}
10801102

@@ -1631,28 +1653,33 @@ public <T extends Identifiable> void putAll(Collection<T> objects)
16311653
{
16321654
Class<T> type = entry.getKey();
16331655
Collection<T> collection = entry.getValue();
1634-
1656+
16351657
// Update the group.
1636-
getGroupSafe(type).putAll(collection);
1637-
1638-
// Update method value caches.
1639-
MethodValueCache<T> methodValueCache =
1640-
(MethodValueCache<T>)methodValueCaches.get(type);
1641-
if (methodValueCache != null)
1658+
int rowsUpdated = getGroupSafe(type).putAll(collection);
1659+
1660+
// If useAffectedRows is enabled, then only update the methodValueCache and
1661+
// notify the listeners if an actual change was persisted.
1662+
if (!useAffectedRows || rowsUpdated > 0)
16421663
{
1643-
for (T object : collection)
1664+
// Update method value caches.
1665+
MethodValueCache<T> methodValueCache =
1666+
(MethodValueCache<T>)methodValueCaches.get(type);
1667+
if (methodValueCache != null)
16441668
{
1645-
methodValueCache.update(object.getId());
1669+
for (T object : collection)
1670+
{
1671+
methodValueCache.update(object.getId());
1672+
}
16461673
}
1647-
}
1648-
1649-
// Notify the listeners.
1650-
final CacheListener[] toNotify = listeners;
1651-
for (CacheListener listener : toNotify)
1652-
{
1653-
for (T object : collection)
1674+
1675+
// Notify the listeners.
1676+
final CacheListener[] toNotify = listeners;
1677+
for (CacheListener listener : toNotify)
16541678
{
1655-
listener.cacheObjectExpired(object.getClass(), object.getId());
1679+
for (T object : collection)
1680+
{
1681+
listener.cacheObjectExpired(object.getClass(), object.getId());
1682+
}
16561683
}
16571684
}
16581685
}

gemini/src/main/java/com/techempower/cache/LruCacheGroup.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,27 @@ public TLongObjectMap<T> map()
144144
}
145145

146146
@Override
147-
public void put(T object)
147+
public int put(T object)
148148
{
149-
super.put(object);
149+
int rowsUpdated = super.put(object);
150150
objects.put(object.getId(), object);
151+
return rowsUpdated;
151152
}
152153

153154
@Override
154-
public void putAll(Collection<T> objectsToPut)
155+
public int putAll(Collection<T> objectsToPut)
155156
{
157+
int rowsUpdated = 0;
156158
for (T object : objectsToPut)
157159
{
158-
put(object);
160+
int c = put(object);
161+
if (c > 0)
162+
{
163+
// Only accumulate positive values;
164+
rowsUpdated += c;
165+
}
159166
}
167+
return rowsUpdated;
160168
}
161169

162170
@Override

gemini/src/main/java/com/techempower/cache/PureMemoryGroup.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,21 @@ public static <T extends Identifiable> Builder<T> of(Class<T> type)
111111
* of entities.
112112
*/
113113
@Override
114-
protected void putPersistent(T object)
114+
protected int putPersistent(T object)
115115
{
116116
// Does nothing.
117+
return 0;
117118
}
118119

119120
/**
120121
* Specialization of CacheGroup.putAllPersistent to disable the persistence
121122
* of entities.
122123
*/
123124
@Override
124-
protected void putAllPersistent(Collection<T> objects)
125+
protected int putAllPersistent(Collection<T> objects)
125126
{
126127
// Does nothing.
128+
return 0;
127129
}
128130

129131
/**

0 commit comments

Comments
 (0)