【问题标题】:eclipselink, advanced query doesn't work as expectedeclipselink,高级查询无法按预期工作
【发布时间】:2013-07-18 19:29:23
【问题描述】:

我正在为 jpa 使用 eclipselink,而迭代器的工作很奇怪...... not 使用高级查询 api 修复它后,我尝试缩小问题范围。 看起来我可能完全误解了手册中的某些内容...为什么以下两个查询有不同的结果?

有问题的代码是这样的:

        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();
        }

如果 useAdvancedQuery==false 则一切正常

如果我启用 useAdvancedQuery 那么它会失败...但是以一种非常奇怪的方式:

  • 事务可以正确地使用迭代器写入值
  • 来自相同相同 entityManagerFactory 的不同事务可以看到这些变化
  • 但是...在关闭这个 EntityManagerFactory 并打开一个新的之后,一切都消失了......

我已经为这个问题写了一个单文件示例:

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");
    }

}

注意:我正在使用 Eclipselink-2.5.0.v20130507-3faac2b

【问题讨论】:

  • 嗨,你能把解决方案发布在和的样子吗?我有一个类似的问题,想从数据库中流出大量数据,一次取 N 个数据。

标签: jpa persistence eclipselink


【解决方案1】:

您正在解包的会话可以访问二级缓存;它将返回只读且不应更改的对象。不会跟踪对这些对象的任何更改,并且由于它们是共享缓存中的对象,因此其他线程可以立即看到它们。

您应该得到的是 UnitOfWork,它将返回托管实体。

【讨论】:

  • 最初我在从迭代器返回之前分离了每个对象..并且仅将修改后的实体合并到事务中的 EntityManager 中(对于这个例子,我删除了那个)..将 Session 更改为 UnitOfWork 解决了问题......谢谢
猜你喜欢
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-19
  • 2018-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多