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
}
}
}
}
Related
SonarLint is showing below errors:
'Use try-with-resources or close this "Statement" in a "finally" clause.'
'Use try-with-resources or close this "Connection" in a "finally" clause.'
blocker errors even though we have closed the Statement stmt, Connection con in finally block.
Please find the sample code.
public String getProductNumber() throws BusinessDelegateException {
String productNo = null;
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
String query = //some query
try {
DataSource ds = getDataSource();
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery(query);
productNo =.......
....................
}catch (Exception e) {
String errorMsg = "Error occured in getProductNumber()";
throw new BusinessDelegateException(errorMsg, e);
}finally{
try {
if(rs != null)
rs.close();
if (stmt != null)
stmt.close();
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return productNo;
}
We were able to fix the issue by modifying the finally block in below manner. But still it seems like repetition of catch blocks. Any other way we can fix this?
finally{
try {
if(rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (stmt != null)
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
Without try-with-resources you can only improve the code by using methods for re-usability, call main method:
closeResources(rs, stmt, con);
Which will call each for each resource a different method for example Statement:
public void closeResource(Statement stmt) {
if (stmt != null) {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
BTW, you better use logger instead of e.printStackTrace()
For complete solution, you can check extensive example which add resources in array and close them in a loop:
for (Closeable resource : resources) {
try {
resource.close();
Use Try-with-resources. This is the best option.
Useful piece of code for Hive JDBC:
Connection con = null;
Statement stmt = null
try {
Class.forName("org.apache.hive.jdbc.HiveDriver");
con = DriverManager.getConnection(connectionUri, userName, password);
stmt = con.createStatement();
stmt.executeUpdate(query);
} catch (ClassNotFoundException cex) {
cex.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
I want to remove try - catch in finally block.
So I tried The try-with-resources Statement.
try (Class.forName("org.apache.hive.jdbc.HiveDriver");
Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement();){
stmt.executeUpdate(query);
} catch (ClassNotFoundException cex) {
cex.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
I think this is not the right way.
Class.forName("org.apache.hive.jdbc.HiveDriver") should not be in try. Should I make a separate try-catch for this?
try {
Class.forName("org.apache.hive.jdbc.HiveDriver");
} catch (ClassNotFoundException cex) {
cex.printStackTrace();
}
try (Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement();){
stmt.executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
Is this right way or am I missing any thing?
The idea behind try-with-ressource is to close an AutoCloseable class.
So every usage of a class which should be closed after using it (a Ressource) can be used with try-with-ressource (like Connection for example). You don't have to take care of closing it manually (in an finally block for example).
So yes, your idea is right:
try/catch for Class.forName("org.apache.hive.jdbc.HiveDriver"); - because this is not AutoCloseable
try-with-ressource for Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement();- because Connection and Statement implement AutoCloseable
Reference:
https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html
When you're using Java 6 or better and the Apache Hive JDBC driver is JDBC 4 compliant or better* then you do not need the Class.forName("org.apache.hive.jdbc.HiveDriver") stuff at all.
Therefore you can just remove the entire try/catch block from your second solution and you're good to go with just:
try (Connection con = DriverManager.getConnection(connectionUri, userName, password);
Statement stmt = con.createStatement()) {
stmt.executeUpdate(query);
} catch (SQLException e) {
e.printStackTrace();
}
* Which is the case for version 1.2.0 or newer of the Hive JDBC driver
Statement Leakage in JDBC:
pstmt =
StatementLeakage : An open JDBC Statement is not closed on all paths. This can cause a transaction or Statement resources to remain active indefinitely, slowing or preventing access to the database by other requests.: for (object created at line = TunnelDBHandler:139, type = java.sql.PreparedStatement), object used at prepareStatement() # TunnelDBHandler:139
dbManager
.getConnection()
.prepareStatement(
"update TUNNEL_STORE set IS_TUNNEL_OPEN=? where TUNNEL_ID=?");
Add a finally block and call close() on all of your ResultSet(s), Statement(s) and Connection(s). As a very rough example,
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// ...
// get a statement for stmt
// get a resultset from the stmt
// ...
while (rs.next()) {
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
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 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;
}