Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java StringBuilder提供了更好的内存分配选择_Java_String_Jpa_Out Of Memory_Heap Memory - Fatal编程技术网

Java StringBuilder提供了更好的内存分配选择

Java StringBuilder提供了更好的内存分配选择,java,string,jpa,out-of-memory,heap-memory,Java,String,Jpa,Out Of Memory,Heap Memory,我使用此StringBuilder在查询中添加内容: Integer lastEntryInEntityId = 1;//acquired through another query Integer tmpValueForEntityId; Integer lastEntryInEntity2Id = 1;//acquired through another query StringBuilder queryString = new StringBuilder("insert into en

我使用此StringBuilder在查询中添加内容:

Integer lastEntryInEntityId = 1;//acquired through another query
Integer tmpValueForEntityId;
Integer lastEntryInEntity2Id = 1;//acquired through another query

StringBuilder queryString = new StringBuilder("insert 
into entity(column,column_1,column_2,column_3) values");
StringBuilder queryString2 = new StringBuilder("insert 
into entity2(column,column_1,column_2,column_3) values");

for(Object[] entityToCopy : entitiesToCopy){
    Entity entity= (Entity )entityToCopy[0];
    tmpValueForEntityId= lastEntryInEntityId ;
    queryString.append("("+ lastEntryInEntityId ++ +","+entity.getProperty()+","+entity[1]+","+entity.getProperty2()+"),");

    for(Entity2 entity2 : entity.getEntity2Collection()){
        queryString2.append("("+lastEntryInEntity2Id ++ +","+tmpValueForEntityId+","+entity.getProperty2()+","+entity.getProperty3()+"),");
    }
}
这段代码占用了太多的时间和内存。在一段时间后(当
要复制的实体太多时)添加到第二个StringBuilder时,它实际上抛出OutOfMemoryException

如何编写此代码以加快速度并减少内存使用?

注意:最好使用Java8解决方案


注2:我使用EntityManager。

您应该使用
concat()
而不是
+
内部
StringBuilder

    for(Object[] entityToCopy : entitiesToCopy){
    Entity entity= (Entity )entityToCopy[0];
    tmpValueForEntityId= lastEntryInEntityId ;
    queryString.append("(").append(lastEntryInEntityId++).append(",").append(entity.getProperty()).append(",").append(entity[1]).append(",").append(entity.getProperty2()).append("),");

    for(Entity2 entity2 : entity.getEntity2Collection()){
        queryString2.append("(").append(lastEntryInEntity2Id ++).append(",").append(tmpValueForEntityId).append(",").append(entity.getProperty2()).append(",").append(entity.getProperty3()).append("),");
    }
}

为了获得更好的性能,请在事务中使用
PreparedStatement

dbCon.setAutoCommit(false);
    var pst = dbCon.prepareStatement("insert into entity (columnID, column_1, column_2, column_3) values (?, ?, ?, ?)";
for(Object[] entityToCopy : entitiesToCopy){
   var entity = (Entity )entityToCopy[0];
   tmpValueForEntityId = lastEntryInEntityId;
   pst.setInt(1, lastEntryInEntityId);
   pst.setString(2, entity.getProperty());
   pst.setString(3, entity[1]);
   pst.setString(4, entity.getProperty2());
   pst.addBatch();
}
pst.executeBatch();
dbCon.commit();
dbCon.setAutoCommit(true);

每个
代表一列。第一个代表ID,第二个代表
列\u 1
,等等。保持每个列的顺序

注意:如果您使用的是1.10之前的Java,请将
var
更改为
PreparedStatement


使用并发连接(在数据库中插入多个线程):

  • 提交后不关闭数据库连接(程序退出时关闭)
  • 插入数据的方法应该是同步的
  • 不要使用
    prepareStatement()
    ,而是使用
    createStatement()
    Pattern
    (regex)来避免SQLInjection
  • 注意:
    PreparedStatement
    良好、快速且安全

    数据库保留一个准备好的语句池,以避免每次都创建新语句。但在并发情况下,在一个线程引用了现有语句->
    PreparedStatement
    之后,另一个线程可以使用它,并且事务处理速度很慢(等待新实例或对现有语句的新引用)。同时,这种情况会发生很多次


    EntityManager示例:

        var em = emf.createEntityManager();
    EntityTransaction transaction = null;
    try {
        transaction = em.getTransaction();
        transaction.begin();
    
        for(Object[] entityToCopy : entitiesToCopy){
             var entity = (Entity )entityToCopy[0];
             ...//insert here
        }
    
        tx.commit();
    } catch (RuntimeException e) {
        if (transaction != null && transaction.isActive()) {
             tx.rollback();
             e.printStackTrace();
        }
    } finally {
        em.close();
    }
    

    您应该在
    StringBuilder

        for(Object[] entityToCopy : entitiesToCopy){
        Entity entity= (Entity )entityToCopy[0];
        tmpValueForEntityId= lastEntryInEntityId ;
        queryString.append("(").append(lastEntryInEntityId++).append(",").append(entity.getProperty()).append(",").append(entity[1]).append(",").append(entity.getProperty2()).append("),");
    
        for(Entity2 entity2 : entity.getEntity2Collection()){
            queryString2.append("(").append(lastEntryInEntity2Id ++).append(",").append(tmpValueForEntityId).append(",").append(entity.getProperty2()).append(",").append(entity.getProperty3()).append("),");
        }
    }
    

    为了获得更好的性能,请在事务中使用
    PreparedStatement

    dbCon.setAutoCommit(false);
        var pst = dbCon.prepareStatement("insert into entity (columnID, column_1, column_2, column_3) values (?, ?, ?, ?)";
    for(Object[] entityToCopy : entitiesToCopy){
       var entity = (Entity )entityToCopy[0];
       tmpValueForEntityId = lastEntryInEntityId;
       pst.setInt(1, lastEntryInEntityId);
       pst.setString(2, entity.getProperty());
       pst.setString(3, entity[1]);
       pst.setString(4, entity.getProperty2());
       pst.addBatch();
    }
    pst.executeBatch();
    dbCon.commit();
    dbCon.setAutoCommit(true);
    

    每个
    代表一列。第一个代表ID,第二个代表
    列\u 1
    ,等等。保持每个列的顺序

    注意:如果您使用的是1.10之前的Java,请将
    var
    更改为
    PreparedStatement


    使用并发连接(在数据库中插入多个线程):

  • 提交后不关闭数据库连接(程序退出时关闭)
  • 插入数据的方法应该是同步的
  • 不要使用
    prepareStatement()
    ,而是使用
    createStatement()
    Pattern
    (regex)来避免SQLInjection
  • 注意:
    PreparedStatement
    良好、快速且安全

    数据库保留一个准备好的语句池,以避免每次都创建新语句。但在并发情况下,在一个线程引用了现有语句->
    PreparedStatement
    之后,另一个线程可以使用它,并且事务处理速度很慢(等待新实例或对现有语句的新引用)。同时,这种情况会发生很多次


    EntityManager示例:

        var em = emf.createEntityManager();
    EntityTransaction transaction = null;
    try {
        transaction = em.getTransaction();
        transaction.begin();
    
        for(Object[] entityToCopy : entitiesToCopy){
             var entity = (Entity )entityToCopy[0];
             ...//insert here
        }
    
        tx.commit();
    } catch (RuntimeException e) {
        if (transaction != null && transaction.isActive()) {
             tx.rollback();
             e.printStackTrace();
        }
    } finally {
        em.close();
    }
    

    我每x次迭代执行一次查询,这样查询就不会变得太大。这解决了我的问题

    int count = 0;
    for(Object[] entityToCopy : entitiesToCopy){
       Entity entity= (Entity )entityToCopy[0];
       tmpValueForEntityId= lastEntryInEntityId ;
       queryString.append("("+ lastEntryInEntityId ++ 
          +","+entity.getProperty()+","+entity[1]+","+entity.getProperty2()+"),");
    
        for(Entity2 entity2 : entity.getEntity2Collection()){
            queryString2.append("("+lastEntryInEntity2Id ++ 
      +","+tmpValueForEntityId+","+entity.getProperty2()+","+entity.getProperty3()+"),");
        }
       count++;
       if(count%2000 == 0 || entitiesToCopy.size() == count){
           em.executeQuery(queryString);
           queryString = "";
           em.executeQuery(queryString2);
           queryString2 = "";
       }
    }
    

    我每x次迭代执行一次查询,这样查询就不会变得太大。这解决了我的问题

    int count = 0;
    for(Object[] entityToCopy : entitiesToCopy){
       Entity entity= (Entity )entityToCopy[0];
       tmpValueForEntityId= lastEntryInEntityId ;
       queryString.append("("+ lastEntryInEntityId ++ 
          +","+entity.getProperty()+","+entity[1]+","+entity.getProperty2()+"),");
    
        for(Entity2 entity2 : entity.getEntity2Collection()){
            queryString2.append("("+lastEntryInEntity2Id ++ 
      +","+tmpValueForEntityId+","+entity.getProperty2()+","+entity.getProperty3()+"),");
        }
       count++;
       if(count%2000 == 0 || entitiesToCopy.size() == count){
           em.executeQuery(queryString);
           queryString = "";
           em.executeQuery(queryString2);
           queryString2 = "";
       }
    }
    

    考虑使用JDBC批处理尝试,使用AppEnter而不是+操作符考虑使用JDBC批处理尝试,使用EntEnter而不是使用EntIngEngor的AppOrthORM AM,是否可以批量处理?避免堆叠代码。越少越好。我从未使用过EntityManagement连续追加方法,这会导致性能下降。内存分配是否更好?StringBuilder.append比+。我正在使用EntityManager,是否可以进行批处理?避免堆叠代码。越少越好。我从未使用过EntityManagement连续追加方法,这会导致性能下降。内存分配是否更好?StringBuilder.append比+。