Java StringBuilder提供了更好的内存分配选择
我使用此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
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比+。