Reputation: 67
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();
}
In the above code myList
is an arrayList
of objects with more than 1.2M entries. I am getting the following error after inserting around 1000 records:
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)
I tried using System.gc()
inside the iterator loop. But I don't think it is a good way to code and also it is consuming lot of CPU cycle.
The above code is a sample code format of my original code.
Upvotes: 2
Views: 7021
Reputation: 691
Avoiding memory leaks with finally block should definitely be addressed first; however if its just a very large resultset; I found this useful:
http://benjchristensen.com/2008/05/27/mysql-jdbc-memory-usage-on-large-resultset/
namely adding
stmt.setFetchSize(Integer.MIN_VALUE);
Before runing stmt.executeQuery();
Upvotes: 0
Reputation: 159096
You run out of memory because you did not close the statement. This is called a resource leak.
Using 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();
}
}
As others have suggested, you should re-use your statement, but it's the missing close()
that's the main issue.
Upvotes: 3
Reputation: 308763
The whole point of PreparedStatement
is to create it once and bind variables.
Here's how I'd suggest that you write it:
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;
}
I left some details for you to figure out (e.g. that close method).
A word of advice: Lose that affection for naming everything "MyFoo". Your code is unreadable with such a naming convention. Think more carefully about how you name things.
Upvotes: 2
Reputation: 21
move the statement out of the loop and user addBatch() and executeBatch instead
Upvotes: 1