The test cases in #4 above demonstrates several topics:
Reusing EntityManager Instances
A first improvement of test_ManyTransactions is to reduce opening and closing entity managers.
Instead of:
for (int m = 0; m < steps; m++) {
em = emf.createEntityManager();
em.setFlushMode(FlushModeType.AUTO);
:
em.close();
}
use the following, if possible:
em = emf.createEntityManager();
em.setFlushMode(FlushModeType.AUTO);
for (int m = 0; m < steps; m++) {
:
}
em.close();
Embedded vs. Inverse Collections
One of the differences between ObjectDB and ORM JPA is the ability of ObjectDB to manage to-many relationships as embedded collections, i.e. collections with content that is stored directly in entity objects. This could be very effective in many cases, but ineffective in others.
In these test cases it would be better to use conventional inverse (mapped by) collection in MyEntity:
@Entity
public static class MyEntity {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "ownerEntity")
private List<MyEntityElement> list = new ArrayList();
public List<MyEntityElement> getList() {
return list;
}
}
@Entity
public static class MyEntityElement {
MyEntity ownerEntity;
@ElementCollection
private List<Float> values;
public void setValues(List<Float> values) {
this.values = values;
}
public List<Float> getValues() {
return values;
}
}
Note that the collection in MyEntity is inverse (mapped by) now but the collection in MyEntityElement, which is small, is still embedded. A large embedded collection, which is modified in high frequency (as in this test case) is inefficient, since every small change requires storing the entire large object again (a MyEntity instance with an embedded collection of up to 10,000 MyEntityElement references).
Untrackable New Objects
JPA implementations have to detect modifications to managed objects automatically in order to apply changes to the database on flush/commit. This could be done by keeping a copy of every managed object and comparing copies to actual objects on every flush or commit, but this is inefficient. Enhanced classes enable tracking object modification when it happens very efficiently. Detecting modification efficiently in collections, such as java.util.ArrayList is done by subclassing these types, so every loaded entity object will have fields of type objectdb.java.util.ArrayList (which can track modifications efficiently like an enhanced class) rather than java.util.ArrayList fields when loaded.
There is a problem however with a new managed object that has never been loaded from the database yet, and therefore includes java.util.ArrayList rather than objectdb.java.util.ArrayList. Usually the effect on performance is reasonable, but test_OneTransaction demonstrates an extreme case in which up to 10,000 new MyEntityElement instances in the persistence context are untrackable and requires comparison on every flush.
To avoid this, we introduce now a new method, con.objectdb.Utilities.newTrackable(em, cls) in ObjectDB 2.6.1_03:
MyEntityElement myEntityElement = new MyEntityElement();
myEntityElement.setValues(Utilities.newTrackable(em, ArrayList.class));
Instead of using java.util.ArrayList (which is untrackable) a user can build a new entity object with the trackable version. Using this method is recommended if the object is expected to remain in a live persistence context after first persistence for a long time.
We will try to demonstrate these ideas in separate posts.