I have a servlet deployed on a Jetty 9 server that connects to a MySQL 5.6.17 server using the Connector/J JDBC driver from http://dev.mysql.com/downloads/connector/j/5.0.html.
This particular servlet fires a SQL statement inside a for loop that iterates around 10 times. I have to include the
DriverManager.getConnection(DB_URL, USER, PASSWORD);
line within this loop because the connection closes automatically after the SQL statement has been executed in every iteration of the loop.
Is there a way to keep the connection open, so that getConnection() need be executed only once before the loop starts and then i can manually close it in the finally block.
I have found many posts on this particular issue, but all refer to the connection pooling concept as the solution. But i am just interested in avoiding the connection being closed automatically after each query execution. Shouldn't this be a simple parameter? I am not facing any particular performance problem right now, but it just seems to be a waste of processor and network cycles.
Servlet Code :
public class CheckPhoneNumberRegistrationServlet extends HttpServlet {
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException {
System.err.println("started CheckPhoneNumberRegistrationServlet");
// define database connection details
final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
final String DB_URL = DatabaseParameters.SlappDbURL;
final String USER = DatabaseParameters.DbServer_Username;
final String PASSWORD = DatabaseParameters.DbServer_Password;
PreparedStatement prpd_stmt = null;
Connection conn = null;
ResultSet rs = null;
int resultValue;
// open a connection
/*try {
conn = DriverManager.getConnection(DB_URL, USER, PASSWORD);
} catch (SQLException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}*/
JsonParser jsparser;
JsonElement jselement;
JsonArray jsrequestarray;
JsonArray jsresponsearray = new JsonArray();
StringBuffer jb = new StringBuffer();
String line = null;
try {
BufferedReader reader = req.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
} catch (Exception e) {
e.printStackTrace();
}
try {
jsparser = new JsonParser();
jselement = (JsonElement) jsparser.parse(jb.toString());
jsrequestarray = jselement.getAsJsonArray();
for (int i = 0; i < jsrequestarray.size(); i++) {
// System.err.println("i : " + i +
// jsrequestarray.get(i).toString());
try {
conn = DriverManager.getConnection(DB_URL, USER, PASSWORD);
prpd_stmt = conn
.prepareStatement("select slappdb.isPhoneNumberRegistered(?)");
prpd_stmt.setString(1, jsrequestarray.get(i).toString()
.replace("\"", ""));
rs = prpd_stmt.executeQuery();
if (rs.first()) {
//System.err.println("result sert from sql server : " + rs.getString(1));
//slappdb.isPhoneNumberRegistered() actually returns Boolean
//But converting the result value to int here as there is no appropriate into to Boolean conversion function available.
resultValue = Integer.parseInt(rs.getString(1));
if(resultValue == 1)
jsresponsearray.add(jsparser.parse("Y"));
else if(resultValue == 0)
jsresponsearray.add(jsparser.parse("N"));
else throw new SQLException("The value returned from the MySQL Server for slappdb.isPhoneNumberRegistered(" + jsrequestarray.get(i).toString().replace("\"", "") + ") was unexpected : " + rs.getString(1) + ".\n");
// System.err.println("y");
}
else throw new SQLException("Unexpected empty result set returned from the MySQL Server for slappdb.isPhoneNumberRegistered(" + jsrequestarray.get(i).toString().replace("\"", "") + ").\n");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (prpd_stmt != null)
prpd_stmt.close();
} catch (SQLException e1) {
}
try {
if (conn != null)
conn.close();
} catch (SQLException e1) {
}
}
}
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
// resp.setContentLength(1024);
resp.getWriter().write(jsresponsearray.toString());
System.err.println(jsresponsearray.toString());
} catch (Exception e) {
// crash and burn
System.err.println(e);
}
The problem is that you're closing the connection inside the for loop. Just move both statements: connection opening and connection close, outside the loop.
conn = DriverManager.getConnection(DB_URL, USER, PASSWORD);
for (int i = 0; i < jsrequestarray.size(); i++) {
try {
//current code...
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (prpd_stmt != null)
prpd_stmt.close();
} catch (SQLException e1) {
}
}
}
try {
if (conn != null)
conn.close();
} catch (SQLException e1) {
}
Related
I was working on a java project and it was working just fine. I was able to make connections. I closed all the connections properly in finally block. Now I am not able to make connections or even open psql in my terminal. How can I make it work as before. Much much appreciated
import java.sql.Connection;
import com.mchange.v2.c3p0.*;
public class MyConnection {
public static Connection getConnection(){
ComboPooledDataSource cpds1 = new ComboPooledDataSource();
String dbDriver = "org.postgresql.Driver";
String dbName = "jdbc:postgresql://localhost/postgres";
cpds1.setJdbcUrl(dbName);
String userName = "user_1";
cpds1.setUser(userName);
String password = "mypass";
cpds1.setPassword(password);
cpds1.setMaxStatements( 180 );
try
{
cpds1.setDriverClass(dbDriver);
return cpds1.getConnection();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
}
This is where I'm calling it
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException
{
PrintWriter writer = response.getWriter();
JSONObject jo = new JSONObject();
JSONObject jObj;
Statement stmt = null;
Connection con = null;
PreparedStatement ps;
ResultSet rs = null;
try
{
jObj = UtilityClass.getJSON(request);
String uname = ((String) jObj.get("uname"));
String pass = ((String) jObj.get("pass"));
String sql = "SELECT * FROM users WHERE username = ?";
try
{
con = MyConnection.getConnection();
System.out.println("Got Connection");
stmt = con.createStatement();
ps = con.prepareStatement(sql);
ps.setString(1, uname);
rs = ps.executeQuery();
if(rs.next())
{
if(BCrypt.checkpw(pass,rs.getString("password")))
{
HttpSession session = request.getSession();
session.setAttribute("uname", uname);
if(session.isNew())
{
System.out.println("new");
}
if(uname.equals("admin"))
{
session.setAttribute("role", "admin");
jo.put("status", "admin");
}
else
{
session.setAttribute("role", "user");
jo.put("status", "authenticate");
}
}
}
writer.print(jo);
}
catch (Exception e)
{
e.printStackTrace();
System.out.println("Not Connected");
}
finally
{
if(rs != null)
{
rs.close();
}
if(stmt != null)
{
stmt.close();
}
if(con != null)
{
con.close();
}
}
}
catch(Exception e)
{
System.out.print("JSON Exception");
}
}
Usually, DB Admins are using pooling technologies on Databases. For PostgreSQL one of the more popularly is a PGBOUNCER. We used PGBOUNCER in our large project, the result is excellent. I recommend it to you. To get more information about the pooling system you can read this link. For About Pooling
I am trying to see the vulnerability of my code with fortify. The report said that I have an issue which said "the function sometimes fails to release a database resource allocated by". Here is the code and in which line the issue pointed. I've tried to close the connection in the finally block but it not solve the issue. How to fix this?
private AnotherService anotherService;
private void create() {
Connection conn = null;
try {
conn = getCon(); // With fortify, there's an issue which said "the function sometimes fails to release a database resource allocated by", and it refers to this line
conn.setAutoCommit(false);
anotherService.myFunction(conn);
// the conn.commit() is inside anotherService, because I have to make one connection
// rest of code
} catch (Exception e) {
e.printStackTrace;
if (null != conn) {
conn.rollback();
}
} finally {
if (null != conn) {
conn.close();
}
}
}
private static Connection getCon() {
Connection connection = null;
try {
Class.forName("org.postgresql.Driver");
connection = DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/dbname",
"username",
"password");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
Addition:
If I use try-with-resource (like this try (Connection conn = getCon()), to automatically close things, how I could call conn.rollback() in the catch block if any exception occured? Since the conn variable declared inside the try-with-resources.
Well, I solve my problem, the close method should call inside try-catch in the finally block, as mentioned in this link.
In case the link broken, here is the code that I use to solve my problem:
Statement stmt = null;
ResultSet rs = null;
Connection conn = getConnection();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery(sqlQuery);
processResults(rs);
} catch (SQLException e) {
// Forward to handler
} finally {
try {
if (rs != null) {rs.close();}
} catch (SQLException e) {
// Forward to handler
} finally {
try {
if (stmt != null) {stmt.close();}
} catch (SQLException e) {
// Forward to handler
} finally {
try {
if (conn != null) {conn.close();}
} catch (SQLException e) {
// Forward to handler
}
}
}
}
I am currently facing connection leak problem in my code (Java , Struts). I have closed all the result sets, prepared statements, callable statements and the connection in the finally blocks of all the methods in my dao. still I face the issue.Additional information is , I am using StructDescriptor.createDescriptor for creating oracle objects. Will it cause any connection leaks? Please advise.
Code below
public boolean updatedDetails(Distribution distribution, String appCode, Connection dbConnection) {
boolean savedFlag = true;
CallableStatement updateStoredProc = null;
PreparedStatement pstmt1 = null;
try {
logger.debug("In DistributionDAO.updatedDistributionDetails");
//PreparedStatement pstmt1 = null;
ARRAY liArray = null;
ARRAY conArray = null;
ARRAY payArray = null;
ArrayDescriptor licenseeArrDesc = ArrayDescriptor.createDescriptor(LICENSEE_TAB, dbConnection);
ArrayDescriptor contractArrDesc = ArrayDescriptor.createDescriptor(DISTRIBUTION_CONTRACT_TAB, dbConnection);
ArrayDescriptor paymentArrDesc = ArrayDescriptor.createDescriptor(DISTRIBUTION_PAYMENT_TAB, dbConnection);
licenseeArray = new ARRAY(licenseeArrDesc, dbConnection, licenseeEleList.toArray());
contractArray = new ARRAY(contractArrDesc, dbConnection, contractEleList.toArray());
paymentArray = new ARRAY(paymentArrDesc, dbConnection, paymentEleList.toArray());
updateStoredProc = dbConnection.prepareCall("{CALL DIS_UPDATE_PROC(?,?,to_clob(?),?,?,?,?)}");
updateStoredProc.setLong(1, distribution.getDistributionId());
updateStoredProc.setString(2, distribution.getId());
updateStoredProc.setString(3, distribution.getNotes());
updateStoredProc.setString(4, distribution.getNotesUpdateFlag());
updateStoredProc.setArray(5, liArray);
updateStoredProc.setArray(6, conArray);
updateStoredProc.setArray(7, payArray);
String sql1="Update STORY set LAST_UPDATE_DATE_TIME= sysdate WHERE STORY_ID = ? ";
pstmt1=dbConnection.prepareStatement(sql1);
pstmt1.setLong(1,distribution.getStoryId());
pstmt1.execute();
List<Object> removedEleList = new ArrayList<Object>();
removedEleList.add(createDeleteElementObject(removedEle, dbConnection));
catch (SQLException sqle) {
savedFlag = false;
} catch (Exception e) {
savedFlag = false;
} finally {
try {
updateStoredProc.close();
updateStoredProc = null;
pstmt1.close();
pstmt1 = null;
dbConnection.close();
} catch (SQLException e) {
}
}
return savedFlag;
}
// Method createDeleteElementObject
private Object createDeleteElementObject(String removedEle,
Connection connection) {
StructDescriptor structDesc;
STRUCT structObj = null;
try {
structDesc = StructDescriptor.createDescriptor(DISTRIBUTION_REMOVED_ELEMENT_OBJ, connection);
if(removedEle != null) {
String[] tmpArr = removedEle.split("\\|");
if(tmpArr.length == 2) {
Object[] obj = new Object[2];
String eleType = tmpArr[0];
long eleId = Integer.parseInt(tmpArr[1]);
obj[0] = eleType.toUpperCase();
obj[1] = eleId;
structObj = new STRUCT(structDesc, connection, obj);
}
}
} catch (ArrayIndexOutOfBoundsException e) {
} catch (NumberFormatException e) {
} catch (SQLException e) {
}
return structObj;
}
Some hints on your code:
You pass a Connection variable into your call but close it inside your call - is the caller aware of that fact? It would be cleaner to get the connection inside your code or return it unclosed (calling method is responsible)
Exceptions are meant to be caught, not ignored - you don't log your exception - you'll never know what happens. I bet a simple e.printStackTrace() in your catch blocks will reveal helpful information.
Use try-with-resource (see this post)
//Resources declared in try-with-resource will be closed automatically.
try(Connection con = getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
//Process Statement...
} catch(SQLException e) {
e.printStackTrace();
}
At the very least put every close inside single try-catch:
} finally {
try {
if(updateStoredProc != null) {
updateStoredProc.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(pstmt1!= null) {
pstmt1.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(dbConnection != null) {
dbConnection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
With this (simplified) code example Eclipse (Kepler SR2) gives a warning for the innermost if-statement (if (con != null)), dead code.
public class DbManager {
public String getSingleString(String query) throws SQLException {
DbManager dbmgr = new DbManager();
Connection con = null;
try {
con = dbmgr.getConnection("user", "pwd", URL);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
if (con != null) {
PreparedStatement pstmt = null;
ResultSet rset = null;
pstmt = con.prepareStatement(query.toString());
rset = pstmt.executeQuery();
if (rset != null && rset.next()) {
return (rset.getString(1));
}
}
}
return null;
}
}
Typically the database connection defined on the line after the try will create a connection and then the offending if-statement will be true. Is the warning about dead code really correct?
If dbmgr.getConnection("user", "pwd", URL); returns an exception, then con will never get assigned a non-null reference.
You initialized con with null. So when an exception will be thrown and your code will reach the catch, con will be null. That is why that check (con != null) does not make sense.
If the connection is successfully created, then that catch statement will never be called so it is dead code, try rearranging it to:
try {
con = dbmgr.getConnection("user", "pwd", URL);
//if (con != null) { <-- not required because of the try and catch
PreparedStatement pstmt = null;
ResultSet rset = null;
pstmt = con.prepareStatement(query.toString());
rset = pstmt.executeQuery();
if (rset != null && rset.next()) {
return (rset.getString(1));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
I realised the problem after running the code a couple of times and bumping into some problems: one } was missing after the catch. It should be:
try {
con = dbmgr.getConnection("cap_x1", "test");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (con != null) {
PreparedStatement pstmt = null;
ResultSet rset = null;
etc. Thank you for your feedback.
In my method show below find bug is specifying Fail to cleanup java.sql.Statement on checked Exception
public int updateSecurityCodeHistoryForMessage(String phone, String securityCodeHistoryId, String messageState, String messageId, String parentMessageId)
{
CaptivePortalLogger.appLog.error(MODULE+"Start : updateSecurityCodeHistoryForMessage::"+messageState);
int result=-1;
String query=null;
Connection con = null;
PreparedStatement pstmt =null;
try
{
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Available Connection : "+ CaptivePortalDBConnection.getNumIdleConnections());
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Active Connection : "+ CaptivePortalDBConnection.getNumActiveConnections() );
con = CaptivePortalDBConnection.getDataSource().getConnection();
CaptivePortalLogger.appLog.error(MODULE+" Before updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: ");
query="UPDATE tblsecuritycodehistory SET messagestate = ?,messageid = ? WHERE securitycodehistoryid = ? AND mobileno = ?";
CaptivePortalLogger.appLog.debug(MODULE + "for updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport Query : "+ query);
pstmt = con.prepareStatement(query);
pstmt.setString(1,messageState); //<b>line 556</b>
pstmt.setString(2,messageId);
pstmt.setString(3,securityCodeHistoryId);
pstmt.setString(4,phone);
result = pstmt.executeUpdate();
CaptivePortalLogger.appLog.error(MODULE+" After updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: result::"+result);
}
catch (Exception e) {
result = -1;
CaptivePortalLogger.traceLog.debug("Got an exception while updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport: ",e);
}
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try
{
if(pstmt!=null)
pstmt.close();
if(con !=null)
con.close();
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
catch(Exception e)
{
CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e);
}
}
CaptivePortalLogger.appLog.error(MODULE+"End : updateSecurityCodeHistoryForMessage");
return result;
}
I find lots of links on stack but none of them able to solve my problem(may be i m not able to understand them properly). Any help will be appreciated.
Thanks in Advance..........
After updaing my finally block with a solution specfied by #Mark problem persists
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try {
if(pstmt!=null)
pstmt.close();
} catch (Exception ex) {
// Log, ignore, etc
}
try {
if(con !=null)
con.close();
} catch (Exception ex) {
// Log, ignore, etc
}
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
After using #Jon suggestion , my problem get resolved. finally resolved code is ::
public int updateSecurityCodeHistoryForMessage(String phone, String securityCodeHistoryId, String messageState, String messageId, String parentMessageId)
{
CaptivePortalLogger.appLog.error(MODULE+"Start : updateSecurityCodeHistoryForMessage::"+messageState);
int result=-1;
String query=null;
Connection con = null;
PreparedStatement pstmt =null;
try
{
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Available Connection : "+ CaptivePortalDBConnection.getNumIdleConnections());
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Active Connection : "+ CaptivePortalDBConnection.getNumActiveConnections() );
con = CaptivePortalDBConnection.getDataSource().getConnection();
CaptivePortalLogger.appLog.error(MODULE+" Before updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: ");
query="UPDATE tblsecuritycodehistory SET messagestate = ?,messageid = ? WHERE securitycodehistoryid = ? AND mobileno = ?";
CaptivePortalLogger.appLog.debug(MODULE + "for updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport Query : "+ query);
try
{
pstmt = con.prepareStatement(query);
pstmt.setString(1,messageState);
pstmt.setString(2,messageId);
pstmt.setString(3,securityCodeHistoryId);
pstmt.setString(4,phone);
result = pstmt.executeUpdate();
}
catch(SQLException e1)
{
CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e1);
}
finally{
if(pstmt!=null)
pstmt.close();
}
CaptivePortalLogger.appLog.error(MODULE+" After updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: result::"+result);
}
catch (SQLException e2) {
result = -1;
CaptivePortalLogger.traceLog.debug("Got an exception while updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport: ",e2);
}
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try
{
if(con !=null)
con.close();
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
catch(SQLException e)
{
CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e);
}
}
CaptivePortalLogger.appLog.error(MODULE+"End : updateSecurityCodeHistoryForMessage");
return result;
}
Look at this code:
if(pstmt!=null)
pstmt.close();
if(con !=null)
con.close();
Now consider that pstmt.close() can throw an exception... which means con.close() wouldn't be called.
If you're using Java 7, use a try-with-resources statement instead, but otherwise you should have a separate try/finally block for each resource.
try {
connection = ...;
try {
statement = ...;
} finally {
// Clean up statement
}
} finally {
// Clean up connection
}
I'd also strongly recommend against catching blanket Exception - it's better to catch specific exceptions which you can actually handle, and let other exceptions propagate up the stack. Also, you appear to be using integer values to signal success or failure of your method - that's not idiomatic Java; exceptions are preferred for error handling, in general.
The problem is that if pstmt.close() throws an Exception, then the connection is never closed.
Either do not close the statement in the finally (as drivers are required to close Statement objects if the Connection is closed), or put both in their own try..catch-block. Eg:
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try {
if(pstmt!=null)
pstmt.close();
} catch (Exception ex) {
// Log, ignore, etc
}
try {
if(con !=null)
con.close();
} catch (Exception ex) {
// Log, ignore, etc
}
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
Firebug is correct.
You should close all your SQL resources in a finally block, using individually wrapped calls to close methods.
You can do it with a utility class:
package persistence;
public class DatabaseUtils {
// similar methods for ResultSet and Connection
public static void close(Statement s) {
try {
if (s != null) {
s.close();
}
} catch (SQLException e) {
// Log the exception
}
}
}
Call the close method in a finally block in the method that created the resource.
Try to cleanup /close resource in separate try/catch/finally block otherwise if any one throw an exception then rest of will be remain unclosed.