首页 文章

StringBuilder可替代更好的内存分配

提问于
浏览
0

我正在使用此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()+"),");
    }
}

此代码需要太多时间和内存 . 它实际上会在一段时间后(当 entitiesToCopy 太多时)添加到第二个StringBuilder时抛出OutOfMemoryException .

How else can I write this code in order to make it faster and use less memory?

注意:首选java 8解决方案 .

注2:我使用EntityManager .

2 回答

  • 3

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

    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,第二个代表 column_1 ,等等 . 保持每个的顺序 .

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


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

    • 提交后不关闭数据库连接(程序退出时关闭)

    • 插入数据的方法应为 synchronized

    • 不要使用 prepareStatement() ,而是使用 createStatement()Pattern (正则表达式)来避免SQL注入 .

    注意: PreparedStatement 好,快,安全 .

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


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

    我每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 = "";
       }
    }
    

相关问题