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();
}
}
Related
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);
}
}
I'm trying to store an sql request into an object so I can load/save information from this object.
Unfortunalty it seems I miss something... But I dunno what :D
When I execute my code I get an error saying :
"java.lang.Integer cannot be cast to [B"
(I catch this message in ClassCastException)
Here is what I do :
public static CatalogueClients chargementClient() throws ClassNotFoundException, IOException, SQLException {
// TODO Auto-generated method stub
Connection dbConnection = null;
Statement statement = null;
CatalogueClients maliste = new CatalogueClients();
try {
dbConnection = OpenConnexion.getDBConnection();
statement = dbConnection.createStatement();
ResultSet result = statement.executeQuery("SELECT * FROM client");
while (result.next()) {
byte[] st = (byte[]) result.getObject(1);
ByteArrayInputStream bais = new ByteArrayInputStream(st);
ObjectInputStream ois = new ObjectInputStream(bais);
maliste = (CatalogueClients) ois.readObject();
ois.close();
bais.close();
}
} catch (SQLException e) {
System.out.println(e.getMessage());
} catch (ClassCastException cce){
System.out.println(cce.getMessage());
} finally {
if (statement != null) {
statement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
return maliste;
}
Here is what CatalogueClients look like :
public class CatalogueClients extends ArrayList<Client> {
private static CatalogueClients instance;
private static final long serialVersionUID = 1L;
public String Afficher() {
return (Input.returnOption("Mes clients: "));
}
public static CatalogueClients getInstance() throws SQLException {
if (instance == null) {
instance = Serialization.chargementClient();
}
return instance;
}
Can you guys please help ?
Thanks
Verify datatype of first column in table (which is returned by query) and modify code accordingly. As per error message mentioned, it is clear that you are receiving Integer value as value of first column.
List<Client> clients = new ArrayList<>();
Client client=null;
try {
dbConnection = OpenConnexion.getDBConnection();
statement = dbConnection.createStatement();
ResultSet result = statement.executeQuery("SELECT * FROM client");
while (result.next()) {
client = new Client();
client.setId(result.getInt(1));
//Map other properties likewise here
clients.add(client);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
} catch (ClassCastException cce){
System.out.println(cce.getMessage());
} finally {
maliste ==clients; // set list here
if (statement != null) {
statement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
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.
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) {
}
It's been a while since I have done any Java programming. And I find my self a bit stuck.
My problem is that I have a pooled db connection in tomcat. That is working nicely. But there is a lot of boiler plate required.
public void init() {
Connection conn = null;
ResultSet rst = null;
Statement stmt = null;
try {
//SETUP
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env/jdbc");
OracleDataSource ds = (OracleDataSource) envContext.lookup("tclsms");
if (envContext == null) throw new Exception("Error: No Context");
if (ds == null) throw new Exception("Error: No DataSource");
if (ds != null) conn = ds.getConnection();
if (conn == null) throw new Exception("Error: No Connection")
message = "Got Connection " + conn.toString() + ", ";
//BODY
stmt = conn.createStatement();
rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");
if (rst.next()) message = rst.getString(1);
//TEAR DOWN
rst.close();
rst = null;
stmt.close();
stmt = null;
conn.close(); // Return to connection pool
conn = null; // Make sure we don't close it twice
} catch (Exception e) {
e.printStackTrace();
//TODO proper error handling
} finally {
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
if (rst != null) {
try {
rst.close();
} catch (SQLException e) {;}
rst = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {;}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {;}
conn = null;
}
} //END FINALLY
} //END INIT
So I want to do the equivalent of passing a method into init that will run in the body of the function. I know I can't do this in Java. But I'm sure there must be a nice way to do this. Or at least a best practice for this sort of thing.
Any help much appreciated.
abstract class UseDBConnectionTask extends Runnable {
private Connection conn;
public UseDBConnectionTask(){
setUp();
}
// should probably refine this to specific exceptions
public abstract void process() throws Exception;
public void run(){
try{
process()
// this should catch specific exceptions
} catch (Exception e){
// handle
} finally {
tearDown();
}
}
Connection getConnection(){
return conn;
}
public void setUp(){
// SETUP here
// set the conn field
}
public void tearDown(){
// TEAR DOWN here
}
}
use like:
UseDBConnectionTask dbTransaction = new UseDBConnectionTask(){
public void process(){
// do processing
// use conn via getConnection()
// eg
Statement stmt = conn.createStatement();
ResultSet rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");
String message = null;
if (rst.next()) message = rst.getString(1);
}
}
new Thread(dbTransaction).start();
The advantage of extending Runnable is that you can then pass this instance into a thread pool or similar.
Just have to be careful of threading issues. It also assumes that the tear down is always the same.
You should prefer delegation to inheritance. The above can/will work but isn't well thought out.
Implementing Runnable on the primary class exposes it for abuse because the 'run()' method is public.
A second improvement is to use to delegate your activity to an interface (and this CAN be passed around like a function pointer whereas extending the class cannot). In addition, it makes it Spring friendly
This allows the action implementer to decide if they want multi-threaded behavior or not. You can inject composites, caching delegates, etc and the primary class is none-the-wiser. This conforms with good design practice of separation of concerns
public class MyClass {
private Action action;
public MyClass (Action action) {
this.action = action;
}
public void connection() {
try{
action.perform()
} catch (Exception e){
// handle
} finally {
tearDown();
}
}
Connection getConnection(){
return conn;
}
private void setUp(){
// SETUP here
// set the conn field
}
private void tearDown(){
// TEAR DOWN here
}
}
interface IDbAction {
public DbActionResult runAction(Connection conn);
}
class DbActionResult {
Statement statement;
ResultSet resultSet;
public DbActionResult(Statement statement, ResultSet resultSet){
this.statement = statement;
this.resultSet = resultSet;
}
public void getStatement(){ return this.statement; }
public void getResultSet(){ return this.resultSet; }
}
public void runAgainstDB(IDbAction action) {
Connection conn = null;
ResultSet rst = null;
Statement stmt = null;
try {
//SETUP
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env/jdbc");
OracleDataSource ds = (OracleDataSource) envContext.lookup("tclsms");
if (envContext == null) throw new Exception("Error: No Context");
if (ds == null) throw new Exception("Error: No DataSource");
if (ds != null) conn = ds.getConnection();
if (conn == null) throw new Exception("Error: No Connection")
message = "Got Connection " + conn.toString() + ", ";
//BODY
DbActionResult actionResult = action.runAction(conn);
//TEAR DOWN
if((rst = actionResult.getResultSet()) != null){
rst.close();
rst = null;
}
if((stmt = actionResult.getStatement()) != null){
stmt.close();
stmt = null;
}
actionResult = null;
conn.close(); // Return to connection pool
conn = null; // Make sure we don't close it twice
} catch (Exception e) {
e.printStackTrace();
//TODO proper error handling
} finally {
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
if (rst != null) {
try {
rst.close();
} catch (SQLException e) {;}
rst = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {;}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {;}
conn = null;
}
} //END FINALLY
} //END
Use like:
IDbAction action = new IDbAction(){
public DbActionResult prcoessAction(Connection conn){
Statement stmt = conn.createStatement();
ResultSet rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");
if (rst.next()) message = rst.getString(1);
return new DbActionResult(stmt, rst);
}
}
runAgainstDB(action);
private void Todo(Context initContext, Context envContext, OracleDataSource ds){
if (envContext == null) throw new Exception("Error: No Context");
if (ds == null) throw new Exception("Error: No DataSource");
if (ds != null) conn = ds.getConnection();
if (conn == null) throw new Exception("Error: No Connection")
message = "Got Connection " + conn.toString() + ", ";
//BODY
stmt = conn.createStatement();
rst = stmt.executeQuery("SELECT 'Success obtaining connection' FROM DUAL");
if (rst.next()) message = rst.getString(1);
//TEAR DOWN
rst.close();
rst = null;
stmt.close();
stmt = null;
conn.close(); // Return to connection pool
conn = null; // Make sure we don't close it twice
} catch (Exception e) {
e.printStackTrace();
//TODO proper error handling
} finally {
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
if (rst != null) {
try {
rst.close();
} catch (SQLException e) {;}
rst = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {;}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {;}
conn = null;
}
} //END FINALLY
}
Then call it from your Init like this this. Todo(initContext,envContext , ds)