Reputation: 1808
i'm using eclipselink for jpa, and the iterator worked strangely... after fixing it by not using the advanced query api i tryed narrow down the problem. it looks like i might be completely misunderstood something in the manual...why the following two queries has different results?
the problematic piece of code is this:
if (useAdvancedQuery) {
// doesn't write to db
ReadAllQuery readAllQuery = new ReadAllQuery(type);
readAllQuery.useCursoredStream(500, 500);
Session session = em.unwrap(Session.class);
scrollableCursor = (CursoredStream) session
.executeQuery(readAllQuery);
} else {
Query query = em.createQuery("SELECT e FROM " + type.getName()
+ " e ORDER BY e.id Desc");
query.setHint("eclipselink.cursor", true);
query.setHint("eclipselink.cursor.page-size", 50);
scrollableCursor = (CursoredStream) query.getSingleResult();
}
if useAdvancedQuery==false then everything works as expected
if i enable useAdvancedQuery then it fails...but in a very strange way:
i've written a one-file example for the problem:
package x;
import java.io.Serializable;
import java.util.*;
import javax.persistence.*;
import junit.framework.Assert;
import org.eclipse.persistence.queries.*
import org.eclipse.persistence.sessions.Session;
@Entity
public class TestEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
private String label;
private static final long serialVersionUID = 1L;
TestEntity() {
}
public TestEntity(String l) {
setLabel(l);
}
public static void main(String[] args) throws ClassNotFoundException {
new Extracted().run();
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
static class Extracted {
// tweakables
boolean useAdvancedQuery = true;
boolean useNewEntityManagers = false;
public <T> Iterator<T> getIterator(Class<T> type) {
final CursoredStream scrollableCursor;
// change this to false..and it will pass
if (useAdvancedQuery) {
// doesn't write to db
ReadAllQuery readAllQuery = new ReadAllQuery(type);
readAllQuery.useCursoredStream(500, 500);
Session session = em.unwrap(Session.class);
scrollableCursor = (CursoredStream) session
.executeQuery(readAllQuery);
} else {
Query query = em.createQuery("SELECT e FROM " + type.getName()
+ " e ORDER BY e.id Desc");
query.setHint("eclipselink.cursor", true);
query.setHint("eclipselink.cursor.page-size", 50);
scrollableCursor = (CursoredStream) query.getSingleResult();
}
return new Iterator<T>() {
@Override
public boolean hasNext() {
return scrollableCursor.hasMoreElements();
}
@Override
public T next() {
if (!scrollableCursor.hasMoreElements()) {
return null;
}
scrollableCursor.clear();
@SuppressWarnings("unchecked")
T c = (T) scrollableCursor.next();
return c;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
private EntityManagerFactory emf;
private EntityManager em;
public void run() {
{
emf = Persistence.createEntityManagerFactory("ptx2");
em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(new TestEntity("a"));
em.persist(new TestEntity("c"));
em.persist(new TestEntity("d"));
em.getTransaction().commit();
System.out.println("asd!");
em.close();
if (useNewEntityManagers)
emf.close();
}
String testStr = "tst" + new Random().nextInt();
{
if (useNewEntityManagers)
emf = getEntityManager();
em = emf.createEntityManager();
em.getTransaction().begin();
Iterator<TestEntity> it = getIterator(TestEntity.class);
while (it.hasNext()) {
TestEntity e = it.next();
e.setLabel(testStr);
// em.merge(e);
}
em.getTransaction().commit();
em.close();
if (useNewEntityManagers)
emf.close();
}
{
if (useNewEntityManagers)
emf = getEntityManager();
checkConsistance(testStr);
System.out.println("persisted in current session - ok");
emf.close();
}
{
System.out.println("persisted after reconnect?");
emf = getEntityManager();
checkConsistance(testStr);
emf.close();
}
System.out.println("passed");
}
private void checkConsistance(String testStr) {
em = emf.createEntityManager();
em.getTransaction().begin();
Iterator<TestEntity> it = getIterator(TestEntity.class);
while (it.hasNext()) {
TestEntity e = it.next();
Assert.assertEquals(testStr, e.getLabel());
}
em.close();
}
}
private static EntityManagerFactory getEntityManager() {
return Persistence.createEntityManagerFactory("ptx2");
}
}
note: i'm using Eclipselink-2.5.0.v20130507-3faac2b
Upvotes: 1
Views: 2016
Reputation: 21145
The session you are unwrapping gives access to the second level cache; it will return objects that are meant to be read-only and should not be changed. Any changes to these objects are not tracked, and since they are the objects from the shared cache, are immediately visible to other threads.
What you should be getting is the UnitOfWork which will return managed entities.
Upvotes: 1