How to close the connection properly? - jdbc

This question has been asked for multiple times and there are a lot of resources talk about this. But it still make me a worry because I think the close() is not working properly.
PreparedStatemet pstmt = null;
try {
pstmt = conn.prepareStatement(query);
...
pstmt.close();
conn.close();
} catch(...) {
...
} finally {
if(pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
pstmt = null;
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
conn = null;
}
}
System.out.println("PreparedStatement: " + pstmt);
System.out.println("Connection: " + conn);
}
So I expected that it would print out null; but it keep print out the query string and connection path to database.

your code here
try {
PreparedStatemet pstmt = null;
creates a pstmt that should not be visible in your finally block, as it is a local variable in another scope.
You probably have another pstmt somewhere outside of your try catch block. which is messing up your check within the finally block.
Try commenting out PreparedStatemet pstmt = null; in your try block to see if you code still builds, that will help you identify where exactly do you have the overriding declaration for pstmt.
EDIT:
Closing a prepared statement / connection would not mean that the values will be reset. Your connection & prepared statements are indeed closed now, since you are not setting them to null , the data values stored inside are still being printed. That should not be a problem.
Although not a biggie, you can set conn and pstmt to null as well when you closed them that would clear the local memory used by these variables as well. But remember, the connection is still already closed when you do a close call.

Related

Oracle connection timeout inside a Azure Function that cancels at 5mins

I have the following lines of code inside a Java function:
try{
context.getLogger().info("Paso001");
Class.forName("oracle.jdbc.driver.OracleDriver");
context.getLogger().info("Paso002");
Connection conn = DriverManager.getConnection(
params.get().getConnection(), params.get().getUser(), params.get().getPassword());
if (conn != null) {
context.getLogger().info("Connected to the database!");
} else {
context.getLogger().log(Level.SEVERE, "No connection to the database!");
return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).body("Error").build();
}
context.getLogger().info("Paso003");
PreparedStatement sentencia = conn.prepareStatement(params.get().getSentence());
int index = 0;
for (Param param : params.get().getParams()) {
index++;
if (param.getType().equals("String")) {
sentencia.setString(index, param.getValue());
} else {
sentencia.setInt(index, Integer.parseInt(param.getValue()));
}
}
ResultSet rs=sentencia.executeQuery();
JSONArray result = JsonHelper.recordList2Json(rs);
context.getLogger().info(result.toString());
return request.createResponseBuilder(HttpStatus.OK).body(result.toString()).build();
} catch(Exception e)
{
context.getLogger().info("Paso00-err");
context.getLogger().log(Level.SEVERE, e.toString());
}
Loging only shows "Paso001" and "Paso002" but connection fails at 300000 ms (5 minutes) because no "Paso00-err" is shown in the logs. I assume that Azure Function is reaching maximum time.
Azure Function is inside a VNET integration and DATABASE is inside another local NET behind an ExpressRoute.
I have assumed that Firewall is correct because opening socket to Host:Port inside the funcion seems ok:
InetAddress IPv4 = null;
try {
IPv4 = InetAddress.getByName(connect.get().getHost());
} catch (UnknownHostException e) {
result = e.toString();
e.printStackTrace();
return request.createResponseBuilder(HttpStatus.OK).body(result.toString()).build();
}
try {
Socket s = new Socket(IPv4, Integer.parseInt(connect.get().getPort()));
result = "Server is listening on port " + connect.get().getPort()+ " of " + connect.get().getHost();
context.getLogger().info(result);
s.close();
}
catch (IOException ex) {
// The remote host is not listening on this port
result = "Server is not listening on port " + connect.get().getPort()+ " of " + connect.get().getHost();
context.getLogger().info(result);
}
Result gets: "Server is listening on port port of host host
Note. I get same error pointing to a public database installed locally.
Is there anything else missing to open? Any ideas?
Edit: I have rewritten code with .NET CORE 3.11...
using (OracleCommand cmd = con.CreateCommand())
{
try
{
log.LogInformation("step001");
con.Open();
log.LogInformation("step002");
cmd.BindByName = true;
cmd.CommandText = sentence;
OracleDataReader reader = cmd.ExecuteReader();
log.LogInformation("step003");
return new OkObjectResult(reader2Json(reader));
}
catch (Exception ex)
{
return new OkObjectResult("Error: "+ex.ToString());
}
}
and similar results but this time exception is going thrown:
Error: Oracle.ManagedDataAccess.Client.OracleException (0x80004005): Connection request timed out
at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)
at Oracle.ManagedDataAccess.Client.OracleConnection.Open()
at Oracli2.Function1.Run(HttpRequest req, ILogger log) in C:\proy\vscode\dot2\Oracli2\Oracli2\Function1.cs:line 50
You can increase the function time out in the hosts.json file, just so you are aware of that, but I dont think increasing it will fix your issue, 5 minutes is a generous time, unless the query you are running here does in-fact take longer than 5 minutes to return!
Can you set the retry_count & retry_delay for your connection string something small (eg: 3 tries) so you know that the time out is not because of trying to do 100 retries and not see the actual underlying error
Other issues could be to do with connectivity, best bet would be to go into the Kudu Console for the console app, open up SSH and via SSH see if you can connect to your oracle db and run a test query from here, if it's all working from here then connectivity is not the issue.

Sonarlint multiple closes

With this code :
Connection connection = null;
PreparedStatement req = null;
try {
connection = DriverManager.getConnection(url, user, password);
req = connection.prepareStatement(SQL);
} finally {
if (connection != null) {
connection.close();
}
if (req != null) {
req.close();
}
}
SonarLint says :
Close this "PreparedStatement" in a "finally" clause on line 5 (req = ...)
And when i close req first :
Close this "Connection" in a "finally" clause on line 4 (connection = ...)
How can I make SonarLint happy ?
Assuming you are using java.sql.Connection, your code can still end up with resources not being closed at the end of the execution.
If you look at the Connection.close() method signature from Java 6 javadoc, you will see that it can throw a SQLException. Consequently, as you are already in the finally block and if an exception occurs while closing, your code will exit the method without closing the request.
Now, if you invert the close order and start with the request, the same thing can happen. Calling close() can fail, then the connection is never closed, as from the finally block you jump once again directly outside the method.
In order to close both resources properly, I would recommend to deal with it like this:
Connection connection = null;
try {
connection = DriverManager.getConnection(url, user, password);
PreparedStatement req = null;
try {
req = connection.prepareStatement(sql);
} finally {
if (req != null) {
req.close();
}
}
} finally {
if (connection != null) {
connection.close();
}
}

stored procedure getting struck from java but working fine from SQL Developer

public void createCostRecord() throws Exception
{
Context ctx = null;
Connection conn = null;
CallableStatement ps = null;
ResultSet rs = null;
boolean spReturn = false;
try{
ctx = new InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("CSMWebAppjndi");
conn = ds.getConnection();
conn.setAutoCommit(true);
String sp = "{call usp_CreateCostRecords(?,?)}";
ps = conn.prepareCall(sp);
ps.setInt(1, 1000);
ps.setInt(2, 2000);
for(int i=0;i<3;i++)
{
ps.executeQuery();
}
} catch (NamingException e)
{
log.error(e,e);
} catch (SQLException e)
{
log.error(e,e);
}
catch(Exception e)
{
log.error(e,e);
}
finally {
if(rs!=null){
rs.close();
}
if(ps!=null){
ps.close();
}
if(conn != null){
conn.close();
}
if(ctx != null ){
ctx.close();
}
}
}
while calling the above method the line number 23 executeQuery works fine for the first iteration of the for loop,
on second iteration of the for loop its getting struck at executeQuery and the procedure never completes execution.
But the weird thing is while i try the same procedure with same input from SQL developer its getting executed for any number of times without any struck.
Anyone help me to understand why the procedure from java is getting struck at second attempt and but its working fine in SQL developer.

Closing ResultSet is must or not?

I have written a query as given below-
Connection dbConnection = null;
PreparedStatement preparedStatement = null;
ResultSet rs = null;
try {
String fetchOneSQL = "select p.NAME from PAPER p where p.PAPERID="+paperId;
dbConnection = icrudResultAnalysis.getConnection();
preparedStatement = dbConnection.prepareStatement(fetchOneSQL);
rs = preparedStatement.executeQuery();
while (rs.next()) {
Paper paper=new Paper();
paper.setName(rs.getString(NAME));
}
// get new records list
preparedStatement=null;
rs=null;
String getListSql="select ib.NAME from ITEMBANK ib where ib.ITEMBANKID="+itemBankId;
preparedStatement = dbConnection.prepareStatement(getListSql);
rs = preparedStatement.executeQuery();
while (rs.next()) {
ItemBank itemBankObj=new ItemBank();
itemBankObj.setName(rs.getString(NAME));
listItemBanks.add(itemBankObj);
}
rs.close();
preparedStatement.close();
dbConnection.close();
} catch (Exception e) {
LOGGER.error("Exception Occured while fetching All record: "
+ e.getMessage());
} finally {
try{
if (rs!=null){
rs.close();
}
}catch(SQLException e)
{
LOGGER.error(RESULTSETCLOSEEXCEPTION + e.getMessage());
}
try {
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (SQLException e) {
LOGGER.error(STATEMENTCLOSEEXCEPTION
+ e.getMessage());
}
try {
if (dbConnection != null) {
dbConnection.close();
}
} catch (SQLException e) {
LOGGER.error(CONNECTIONCLOSEEXCEPTION
+ e.getMessage());
}
}
In above code i have used single resultset for two select statement by creating ResulSet rs =null . Is it good practice? Or i have to close ResultSet each time? What is difference between closing ResultSet and making ResultSet null?
All resources MUST BE CLOSED after use using .close() method! And resultSet is not an exception, except in this case (from ResultSet javadoc):
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
In your case you have to manual .close() the first opened resultset, but not necessary the second used; making a resultSet = null only set reference to variable resultSet equals null, no more no less.
If you are using Java7, Resultset is implementing AutoCloseable and you can use this feature to rewrite your code in cleaner way (look Oracle doc)
When you are re-using resources(resultSet,PrepareStatement),they must be closed first...Instead of setting prepare statement to NULL.You must close it and it will automatically close the result set.There is no need to explicitly close the result set.

DD anomaly, and cleaning up database resources: is there a clean solution?

Here's a piece of code we've all written:
public CustomerTO getCustomerByCustDel(final String cust, final int del)
throws SQLException {
final PreparedStatement query = getFetchByCustDel();
ResultSet records = null;
try {
query.setString(1, cust);
query.setInt(2, del);
records = query.executeQuery();
return this.getCustomer(records);
} finally {
if (records != null) {
records.close();
}
query.close();
}
}
If you omit the 'finally' block, then you leave database resources dangling, which obviously is a potential problem. However, if you do what I've done here - set the ResultSet to null outside the **try** block, and then set it to the desired value inside the block - PMD reports a 'DD anomaly'. In the documentation, a DD anomaly is described as follows:
DataflowAnomalyAnalysis: The dataflow analysis tracks local definitions, undefinitions and references to variables on different paths on the data flow.From those informations there can be found various problems. [...] DD - Anomaly: A recently defined variable is redefined. This is ominous but don't have to be a bug.
If you declare the ResultSet outside the block without setting a value, you rightly get a 'variable might not have been initialised' error when you do the if (records != null) test.
Now, in my opinion my use here isn't a bug. But is there a way of rewriting cleanly which would not trigger the PMD warning? I don't particularly want to disable PMD's DataFlowAnomalyAnalysis rule, as identifying UR and DU anomalies would be actually useful; but these DD anomalies make me suspect I could be doing something better - and, if there's no better way of doing this, they amount to clutter (and I should perhaps look at whether I can rewrite the PMD rule)
I think this is clearer:
PreparedStatement query = getFetchByCustDel();
try {
query.setString(1, cust);
query.setInt(2, del);
ResultSet records = query.executeQuery();
try {
return this.getCustomer(records);
} finally {
records.close();
}
} finally {
query.close();
}
Also, in your version the query doesn't get closed if records.close() throws an exception.
I think that DD anomaly note is more bug, than a feature
Also, the way you free resources is a bit incomplete, for example
PreparedStatement pstmt = null;
Statement st = null;
try {
...
} catch (final Exception e) {
...
} finally {
try{
if (pstmt != null) {
pstmt.close();
}
} catch (final Exception e) {
e.printStackTrace(System.err);
} finally {
try {
if (st != null) {
st.close();
}
} catch (final Exception e) {
e.printStackTrace(System.err);
}
}
}
moreover this is not right again, cuz you should close resources like that
PreparedStatement pstmt = null;
Throwable th = null;
try {
...
} catch (final Throwable e) {
<something here>
th = e;
throw e;
} finally {
if (th == null) {
pstmt.close();
} else {
try {
if (pstmt != null) {
pstmt.close();
}
} catch (Throwable u) {
}
}
}

Resources