java - StringBuilder 替代方案可实现更好的内存分配

标签 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 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。

我还能如何编写此代码以使其更快并使用更少的内存?

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

注2:我使用EntityManager。

最佳答案

您应该在 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

<小时/>

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

  1. 提交后不要关闭数据库连接(程序退出时关闭)
  2. 插入数据的方法应该同步
  3. 不要使用 prepareStatement(),而是使用 createStatement()Pattern(正则表达式)以避免 SQL 注入(inject)。

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

关于java - StringBuilder 替代方案可实现更好的内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50923878/

相关文章:

string - PHPStorm 中的复制和粘贴字符串(波斯语、阿拉伯语)是错误的

C++ 字符串 - 使用初始化列表构造函数时的奇怪行为

java - 如何为所有实体定义 allocationSize 和 initialValue

java - 当我运行 scala 应用程序时如何修复 "NoClassDefFoundError: midterm/Main"?

java - 如何使用 Gson 以十六进制表示整数?

java - Name 和 FriendlyName 有什么区别?

c++ - 当我调用不相关的方法时,c 字符串的值发生变化

java - java中使用JPA(JpaDaoSupport)调用存储过程

java - 有没有办法将实体加载到派生类的实例中?

java - rxjava 2 中 BackpressureStrategy.BUFFER 和 onBackpressureBuffer 运算符之间的区别