Skip to content

Commit 75cd594

Browse files
committed
added store.callInReadTx()
1 parent 84622b7 commit 75cd594

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

objectbox-java/src/main/java/io/objectbox/BoxStore.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private static void verifyNotAlreadyOpen(String canonicalPath) {
210210
}
211211
}
212212
if (!openFiles.add(canonicalPath)) {
213-
throw new DbException("Another BoxStore is still open for this directory: " + canonicalPath+
213+
throw new DbException("Another BoxStore is still open for this directory: " + canonicalPath +
214214
". Hint: for most apps it's recommended to keep a BoxStore for the app's life time.");
215215
}
216216
}
@@ -492,6 +492,43 @@ public void runInReadTx(Runnable runnable) {
492492
}
493493
}
494494

495+
/**
496+
* Calls the given callable inside a read(-only) transaction. Multiple read transactions can occur at the same time.
497+
* This allows multiple read operations (gets) using a single consistent state of data.
498+
* Also, for a high number of read operations (thousands, e.g. in loops),
499+
* it is advised to run them in a single read transaction for efficiency reasons.
500+
* Note that any exception thrown by the given Callable will be wrapped in a RuntimeException.
501+
*/
502+
public <T> T callInReadTx(Callable<T> callable) {
503+
Transaction tx = this.activeTx.get();
504+
// Only if not already set, allowing to call it recursively with first (outer) TX
505+
if (tx == null) {
506+
tx = beginReadTx();
507+
activeTx.set(tx);
508+
try {
509+
return callable.call();
510+
} catch (Exception e) {
511+
throw new RuntimeException("Callable threw exception", e);
512+
} finally {
513+
activeTx.remove();
514+
515+
// TODO That's rather a quick fix, replace with a more general solution
516+
// (that could maybe be a TX listener with abort callback?)
517+
for (Box box : boxes.values()) {
518+
box.readTxFinished(tx);
519+
}
520+
521+
tx.close();
522+
}
523+
} else {
524+
try {
525+
return callable.call();
526+
} catch (Exception e) {
527+
throw new RuntimeException("Callable threw exception", e);
528+
}
529+
}
530+
}
531+
495532
/**
496533
* Like {@link #runInTx(Runnable)}, but allows returning a value and throwing an exception.
497534
*/

tests/objectbox-java-test/src/main/java/io/objectbox/TransactionTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,26 @@ public void run() {
298298
assertEquals(1, counts[1]);
299299
}
300300

301+
@Test
302+
public void testCallInReadTx() {
303+
final Box<TestEntity> box = getTestEntityBox();
304+
box.put(new TestEntity());
305+
long[] counts = store.callInReadTx(new Callable<long[]>() {
306+
@Override
307+
public long[] call() throws Exception {
308+
long count1 = store.callInReadTx(new Callable<Long>() {
309+
@Override
310+
public Long call() throws Exception {
311+
return box.count();
312+
}
313+
});
314+
return new long[]{box.count(), count1};
315+
}
316+
});
317+
assertEquals(1, counts[0]);
318+
assertEquals(1, counts[1]);
319+
}
320+
301321
@Test
302322
public void testRunInReadTxAndThenPut() {
303323
final Box<TestEntity> box = getTestEntityBox();

0 commit comments

Comments
 (0)