simple mysql/jdbc code causing a memory leak? - java

I'm trying to analyze a heap dump to find a memory leak for the first time. I'm opening up the heap dump using MAT and right away it's pretty clear it's one object? that is taking up almost the entire heap and it's a sql class com.mysql.cj.jdbc.ConnectionImpl.
Since sql is really used in only one part of my code it basically has to be something with this small bit of code here...
static Connection getDBconn() {
Connection conn = null;
while (conn == null) {
try {
conn = DriverManager.getConnection(serverURL, user, pass);
} catch (SQLException e) {
Logger.logError(e);
}
}
return conn;
}
static void update(String sql) {
while (currConn == null)
currConn = getDBconn();
boolean error = false;
do {
try {
currConn.createStatement().executeUpdate(sql);
} catch (SQLException e) {
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
currConn = getDBconn();
Logger.logError(e);
error = true;
}
} while (error);
}
static ResultSet query(String sql) {
while (currConn == null)
currConn = getDBconn();
ResultSet rs = null;
while (rs == null) {
try {
rs = currConn.createStatement().executeQuery(sql);
} catch (SQLException e) {
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
currConn = getDBconn();
Logger.logError(e);
}
}
return rs;
}
What this code is supposed to do is basically wrap query/update statements inside some methods to ensure that each command is always carried out eventually, even when an error comes up. My program will be running for long amounts of time with many requests, and i want to ensure it deals with all possible problems automatically without interrupting the program.
What i have written will work for about an hour or so and then i'll get a out of memory error even when i have my heap set to like 8gb which is obviously overkill. I should also note i'm not getting any sql errors so it's not even getting into the catch blocks. Clearly there is some sort of leak with this code but i'm having trouble figuring out what it could be. Any advice would be appreciated and i can provide more information on the heap dump if needed.

You are getting connection when you don't need it twice
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
--> currConn = getDBconn();
Logger.logError(e);
Just remove currConn = getDBconn() after currConn.close(); and you won't have connection leak.
Better yet, close connection on finally even if no error occurred:
try {
rs = currConn.createStatement().executeQuery(sql);
} catch (SQLException e) {
Logger.logError(e);
finally{
try {
currConn.close();
} catch (SQLException e1) {
Logger.logError(e1);
}
}
Also create a method to prevent code duplication and different implementation of closing connection.

Related

Operation not allowed after ResultSet closed during while loop

I'm having a problem with Resultset during while loop. It's giving me an error java.sql.SQLException: Operation not allowed after ResultSet closed and I can't figure this out. Can anyone help me out? Thanks!
public static void CandidatesPartyList_JComboBox() {
try {
conn1 = VotingSystem.con();
ps = conn1.prepareStatement("SELECT * FROM partylist WHERE p_status = 'Active' ORDER BY p_name ASC");
rs = ps.executeQuery();
candidates_filter_partylist.removeAllItems();
candidates_filter_partylist.addItem("- Select PartyList -");
while (rs.next()) { **<< The problem is coming from here**
candidates_filter_partylist.addItem(rs.getString("p_name"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (conn1 != null) {
try {
conn1.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
You've got static variables named conn1, ps, and rs. Static means there is only one variable for the entire virtual machine.
Clearly then, CandidatesPartyList_JComboBox is called twice by different threads and thus the variables are overwritten.
The solution is: None of those things should be fields. They should be local variables, and you should be using try-with-resources, which makes this code less than half the size and fixes the problem. Let's also fix the bad error handling ('print the stack trace' is not handling things, so never write that and update your IDE templates).
public static void CandidatesPartyList_JComboBox() {
try (Connection c = VotingSystem.con();
PreparedStatement ps = c.prepareStatement("SELECT * FROM partylist WHERE p_status = 'Active' ORDER BY p_name ASC");
ResultSet rs = ps.executeQuery()) {
candidates_filter_partylist.removeAllItems();
candidates_filter_partylist.addItem("- Select PartyList -");
while (rs.next()) {
candidates_filter_partylist.addItem(rs.getString("p_name"));
}
} catch (SQLException e) {
throw new RuntimeException("Unhandled", e);
}
}

rollback mysql transcations from multiplate methods GWT

I'm trying to figure out how to rollback commits from multiple methods. I want to do something like the following (editing for brevity)
public void testMultipleMethodRollback() throws DatabaseException {
Connection conn = connect();
fakeMethodRollback1();
fakeMethodRollback2();
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
and currently all my methods are formatted like this
public void fakeMethodRollback1() throws DatabaseException {
Connection con = connect();
PreparedStatement ps = null;
ResultSet rs = null;
// insert some queries
try {
String query = "some query";
ps = conn.prepareStatement(query);
ps.executeUpdate(query);
query = "some query";
ps = conn.prepareStatement(query);
ps.executeUpdate(query);
con.commit();
} catch (SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
throw new DatabaseException(e);
} finally {
close(rs, ps, conn);
}
}
because I want to be able to use the other methods independently, how can I do a rollback where if one method fails, the others will roll back? I fear I have my whole class setup wrong or at least wrong enough that this can't be accomplished without major work. I can't change the methods to return a connection, because half of my methods are get methods, which are already returning other data. Any ideas?

Efficient JDBC connection management in a stateless session bean

I have a stateless session bean a method of which is used repetitively for running an SQL query within a plain JDBC connection. To avoid having to open and close connections too frequently, I came up with the following approach and wondering if it is a good practice:
I open the connection once in a method annotated #PostConstruct and close the connection in another method annotated #PreDestroy
The code works fine with no apparent memory leaks or any issues that I know of - just wondering if more experienced developers would agree if it is a good practice.
#PostConstruct
public void initBean() {
try {
conn = Connector.getConnection();
} catch (Exception e) {
// Handle errors for Class.forName
e.printStackTrace();
}
}
public String runTheQuery(String sql) {
String result ="";
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
result = rs.getString(1);
rs.close();
pstmt.close();
} catch (SQLException se) {
// Handle errors for JDBC
}
return result;
}
#PreDestroy
public void endingTitles() {
System.out.println("Closing the JDBC connection...");
try {
rs.close();
conn.close();
pstmt.close();
} catch (SQLException se) {
// Handle errors for JDBC
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// finally block used to close resources
try {
if (pstmt != null)
pstmt.close();
} catch (SQLException se2) {
}// nothing we can do
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}// end finally try
}// end try
}
The best solution is to use DataSource
#Resource(mappedName="java:/DefaultDS")
DataSource dataSource;
public String runTheQuery(String sql) throws SQLException
Connection con = dataSource.getConnection();
try {
...
} finally {
con.close();
}
}
Data sources normally always have a minimum number of open connections, so in most cases there will be no real overhead getting a connection from a data source.
So it's only a valid practice, if you have measured before, and it it really solves an existing performance problem.
Otherwise it's not common, and therefore it's something like premature performance optimization.
Data sources offer additonal functionality: For example to check a connection, if it's still valid, before it gets injected. If you did it yourself, you would have to reimplement it. And there are possibly errors in that code.

java.sql.SQLException: ORA-01000: maximum open cursors exceeded while truncating tables

I get this exception while truncating all table in a schema.
I truncate 3 schema in my Java code and first method get list of table names from given schema name and second method executes "TRUNCATE TABLE table_name" query.
I confused about my code always succesful while truncating first and third schema. But while executing on second schema I get ORA-01000 error.
My truncate code is
private void truncateTable(Connection conn, String tableName) {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(Utility.TRUNCATE_TABLE + tableName);
ps.executeUpdate();
} catch (SQLException e) {
log.error("SQLException occured while getting table names from schema", e);
} finally {
Utility.free(ps, null, null);
}
}
private List<String> getAllTableNames(Connection conn) {
PreparedStatement ps = null;
ResultSet rs = null;
List<String> list = new ArrayList<String>();
try {
ps = conn.prepareStatement(Utility.SELECT_ALL_TABLE_NAMES);
rs = ps.executeQuery();
while (rs.next()) {
list.add(rs.getString("TABLE_NAME"));
}
} catch (SQLException e) {
log.error("SQLException occured while getting table names from schema", e);
} finally {
Utility.free(ps, rs, null);
}
return list;
}
public static void free(PreparedStatement ps, ResultSet rs, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.error("Error occurred while closing ResultSet",e);
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
log.error("Error occurred while closing PreparedStatement",e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
log.error("Error occurred while closing Connection",e);
}
}
}
What is the wrong about code or is it about schema configuraiton in Oracle?
How can I solve this?
If are you iterating over the List generated by getAllTableNames and calling truncateTable in a tight loop, your free calls in the finally block might just be delayed and stacking up to an extent that they aren't clearing fast enough for the next iterations - since you only know the finally will be called at some point, not necessarily immediately and before control is returned to the caller.
The schema size would make a difference to that, so it might make sense that a small schema succeeds and a large one fails. If that is what's happening then you should call free inside the try, as well as in the finally:
private void truncateTable(Connection conn, String tableName) {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(Utility.TRUNCATE_TABLE + tableName);
ps.executeUpdate();
Utility.free(ps, null, null);
ps = null;
} catch (SQLException e) {
log.error("SQLException occured while getting table names from schema", e);
} finally {
if (ps != null) {
Utility.free(ps, null, null);
}
}
}
If Utility.free checks whether ps is null then that check in the finally block might be redundant, but without it, free would be called twice if there is no SQLException.
Check out the code and make sure you are closing the cursors after being used. If the problem still persists please set OPEN_CURSORS to some more value.

Is that the best way to release SQLite connection in Java?

I need a good way to close SQLIte connections in Java. After a few suggestion by other users I decided to add to my code a finally block to be sure that closing operation are always executed.
public static boolean executeQuery(String query)
{
Connection conn = null;
Statement stmt = null;
try
{
Class.forName("org.sqlite.JDBC");
conn = DriverManager.getConnection(Global.dbPath);
stmt = conn.createStatement();
stmt.execute(query);
return true;
}
catch(ClassNotFoundException e)
{
System.out.println(e);
return false;
}
catch(SQLException e)
{
System.out.println(e);
return false;
}
finally
{
try
{
stmt.close();
conn.close();
return true;
}
catch (SQLException ex)
{
System.out.println ("Errore closing connections");
return false;
}
}
}
I'm not sure that this is the best solution.
How can I optimize this for readability?
A few comments; nutshells:
Separate the SQL exceptions from the reflection exception.
Are your SQL exceptions recoverable? If not, throw an app-specific RuntimeException.
Wrap up the connection and statement close exceptions in a utility method, yours or a 3rd party's.
Don't short-change exception handling; dump the stack trace.
This leads to the following:
public static boolean executeQuery(String query) {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
throw new DbException("Could not find JDBC driver", e);
}
Connection conn = null;
Statement stmt = null;
try {
conn = DriverManager.getConnection(Global.dbPath);
stmt = conn.createStatement();
stmt.execute(query);
return true;
} catch(SQLException e) {
throw new DbException("Exception during statement execution", e);
} finally {
DbUtils.closeQuietly(conn);
DbUtils.closeQuietly(stmt);
}
}
(I'm using Apache Commons' DbUtils for its closeQuietly, it checks for null (yours didn't). Your own version might throw an app-specific exception as I do here with DbException. This wraps up all your DB-related exceptions into a single exception class, which may or may not be what you need.
If you want to make sure a command is executed you have to put it alone into a try catch block:
try {
stmt.close();
}
catch (Exception ex) {
}
try {
conn.close();
}
catch (Exception ex) {
System.out.println ("Error closing connections");
return false;
}

Categories