【问题标题】:How to improve performance of Updating data using JPA如何使用 JPA 提高更新数据的性能
【发布时间】:2015-08-16 16:09:41
【问题描述】:

我正在使用 EJB 和容器管理的 EM(为了进行本地测试,我在这里创建了 EM)。 我有一个需求,我需要根据某些情况更新数据库,我的问题是 更新需要很长时间,如何减少它?

我尝试了两种方法 1> 更新查询 2> 实体更新

如果我犯了任何错误,或者存在任何其他方法,请告诉我。

注意:更新代码如下

    public class Test {
    private static final int OaOnaccount = 0;
    private static final int ArrayList = 0;
    private static EntityManagerFactory emf;
    private static EntityManager em;
    static int TEST_SIZE = 20000/4;

    public static void main(String[] args) {
//       createBulk();
        createUpdateQuery();
//       update();

    }

    private static void createUpdateQuery() {
        long st = System.currentTimeMillis();
        emf = Persistence.createEntityManagerFactory("Jpa");
        em = emf.createEntityManager();
        System.out.println("---- createUpdateQuery ---");
        EntityTransaction tx = em.getTransaction();
        Query query = em.createQuery("SELECT p FROM OaOnaccount p");
        tx.begin();
        java.util.Vector<OaOnaccount> list = (java.util.Vector<OaOnaccount>) query.getResultList();
        for (int i = 0; i < list.size(); i++) {
            String m = 1000000 + (i / 20) + "";
            query = em
                    .createQuery("UPDATE OaOnaccount p SET p.status='COMPLETED', p.billingDoc='12112ABCS' WHERE p.crDrIndicator='H' AND p.status ='OPEN' AND p.documentNumber="+ m);
            query.executeUpdate();
        }

        em.flush();
        tx.commit();

        long et = System.currentTimeMillis();

        System.out.println("Test.createUpdateQuery() Time " + (et - st));

    }

    private static void update() {

        long st = System.currentTimeMillis();
        emf = Persistence.createEntityManagerFactory("Jpa");
        em = emf.createEntityManager();
        System.out.println("---- update ---");
        EntityTransaction tx = em.getTransaction();
        Query query = em.createQuery("SELECT p FROM OaOnaccount p");
        tx.begin();

        java.util.Vector<OaOnaccount> list = (java.util.Vector<OaOnaccount>) query
                .getResultList();
        for (int i = 0; i < list.size(); i++) {
            String m = 1000000 + (i / 20) + "";
            query = em
                    .createQuery("SELECT p FROM OaOnaccount p WHERE p.crDrIndicator='H' AND p.status ='OPEN' AND p.documentNumber="
                            + m);
            java.util.Vector<OaOnaccount> listEn = (java.util.Vector<OaOnaccount>) query
                    .getResultList();
            for (int j = 0; j < listEn.size(); j++) {
                listEn.get(j).setBillingDoc("12112ABCS");
                listEn.get(j).setStatus("COMPLETED");
            }
        }

        em.flush();
        tx.commit();

        long et = System.currentTimeMillis();

        System.out.println("Test.Update() Time " + (et - st));

    }

    public static void createBulk() {
        long st = System.currentTimeMillis();
        emf = Persistence.createEntityManagerFactory("Jpa");
        em = emf.createEntityManager();
        System.out.println("-------");
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        for (int i = 0; i < TEST_SIZE; i++) {
            OaOnaccount entity = new OaOnaccount();
            entity.setId("ID-" + i);
            entity.setCrDrIndicator(i % 2 == 0 ? "H" : "S");
            entity.setDocumentNumber(1000000 + (i / 20) + "");
            entity.setAssignment(89000000 + (i / 27) + "");
            entity.setStatus("OPEN");
            em.persist(entity);
        }
        em.flush();
        tx.commit();

        long et = System.currentTimeMillis();

        System.out.println("Test.createBulk() Time " + (et - st));

    }

}

【问题讨论】:

    标签: java jpa sql-update jpql entitymanager


    【解决方案1】:

    您应该为每 n 次迭代执行 em.flush()。例如,如果 n- db 交互次数太少,因此执行代码会变慢。如果 n- 太高,太多的对象驻留在内存中,因此更多的交换因此执行代码的速度变慢。请适度选择n值并应用。我尝试更新 240 万条记录,我遇到了同样的问题。

          for (int i = 0; i < list.size(); i++) {
            String m = 1000000 + (i / 20) + "";
            query = em
                    .createQuery("UPDATE OaOnaccount p SET p.status='COMPLETED', p.billingDoc='12112ABCS' WHERE p.crDrIndicator='H' AND p.status ='OPEN' AND p.documentNumber="+ m);
            query.executeUpdate();
            if(i%100==0){// 100 to just to show example-- % operation is costly. you can use better logic to flush. frequent flushing is necessary 
             em.flush();
              }
        }
    

    【讨论】:

      【解决方案2】:

      检查您在 OaOnaccount 表上的索引,特别确保 p.statusp.documentNumber 上有一个索引,或者更好的是使用 (status, documentNumber) 的组合索引

      【讨论】:

      • 是的,你的解决方案帮助了我,时间从 244790 毫秒减少到 167525 毫秒但是任何其他方法 bcos inseart 需要 3807 毫秒,但更新量很大
      • 好吧,也许您需要进一步调整您的数据库。你用的是什么数据库?表中有多少行?您可能需要对数据库进行一些内存调整。我知道使用 MySQL,my.cnf 中用于各种排序缓冲区的内存设置会对您的性能产​​生巨大影响。
      • Oracle 无法帮助您,最好向了解 oracle 的人提出这个问题,我认为问题不在于 Java/JPA。您也可以创建一个空表并尝试一下,看看是否加快了速度
      猜你喜欢
      • 1970-01-01
      • 2021-11-10
      • 2018-12-10
      • 2018-10-19
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多