内存不足错误:Java堆空间 - PreparedStatement MySQL

时间:2015-09-10 20:38:07

标签: java mysql

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周期。

上面的代码是我原始代码的示例代码格式。

4 个答案:

答案 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()之前;