void insert(ArrayList myList){
conn = openDBConnection(); //Database Connection
Iterator iterator = myList.iterator();
while(iterator.hasNext()){
insertIntoDB((myClass)iterator.next(),conn);
}
closeDBConnection();
}
void insertIntoDB(myClass myObject, Connection conn){
String query = "insert into myTable values(?,?)";
PreparedStatement myStatement = conn.prepareStatement(query);
myStatement.setInt(1,myObject.getMyKey());
myStatement.setInt(2,myObject.getMyValue());
myStatement.execute();
}
在上面的代码myList
中,arrayList
个对象的条目数超过1.2M。插入大约1000条记录后,我收到以下错误:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.mysql.jdbc.PreparedStatement.<init>(PreparedStatement.java:437)
at com.mysql.jdbc.Connection.clientPrepareStatement(Connection.java:2187)
at com.mysql.jdbc.Connection.prepareStatement(Connection.java:4829)
at com.mysql.jdbc.Connection.prepareStatement(Connection.java:4734)
at com.att.research.space.SpaceDaoImpl.insertMapping(SpaceDaoImpl.java:99)
at com.att.research.space.ElementMappingLoader.insertMappingData(ElementMappingLoader.java:68)
at com.att.research.space.CorrelationEngine.loadMappingFiles(CorrelationEngine.java:69)
at com.att.research.space.CorrelationEngine.main(CorrelationEngine.java:25)
我尝试在迭代器循环中使用System.gc()
。但我不认为这是一种很好的代码编写方式,而且它耗费了大量的CPU周期。
上面的代码是我原始代码的示例代码格式。
答案 0 :(得分:2)
PreparedStatement
的重点是创建一次并绑定变量。
以下是我建议你写它的方法:
private static final String INSERT_QUERY = "insert into myTable values(?,?)";
public int insert(Connection c, List<MyClass> myList) {
int numRows = 0;
PreparedStatement ps = null;
try {
ps = c.prepareStatement(INSERT_QUERY);
for (MyClass x : myList) {
ps.setInt(1, x.getMyKey());
ps.setInt(2, x.getMyValue());
numRows += ps.executeUpdate();
}
} finally {
close(ps);
}
return numRows;
}
我留下了一些细节供你弄清楚(例如那种关闭方法)。
建议:失去对所有“MyFoo”命名的感情。使用这样的命名约定,您的代码是不可读的。更仔细地考虑如何命名。
答案 1 :(得分:2)
由于未关闭声明,因此内存不足。这称为资源泄漏。
使用try-with-resources(Java 7 +):
void insertIntoDB(myClass myObject, Connection conn){
String query = "insert into myTable values(?,?)";
try (PreparedStatement myStatement = conn.prepareStatement(query)) {
myStatement.setInt(1,myObject.getMyKey());
myStatement.setInt(2,myObject.getMyValue());
myStatement.execute();
}
}
Pre-Java 7:
void insertIntoDB(myClass myObject, Connection conn){
String query = "insert into myTable values(?,?)";
PreparedStatement myStatement = conn.prepareStatement(query);
try {
myStatement.setInt(1,myObject.getMyKey());
myStatement.setInt(2,myObject.getMyValue());
myStatement.execute();
} finally {
myStatement.close();
}
}
正如其他人所建议的那样,你应该重复使用你的陈述,但缺少close()
这是主要问题。
答案 2 :(得分:1)
将语句移出循环,用户使用addBatch()和executeBatch
答案 3 :(得分:0)
使用finally块避免内存泄漏应该首先解决。但是,如果结果集非常大;我发现这很有用:
http://benjchristensen.com/2008/05/27/mysql-jdbc-memory-usage-on-large-resultset/
即添加
stmt.setFetchSize(Integer.MIN_VALUE);
在运行stmt.executeQuery()之前;