Currently we have a java application which have many different queries and not all are ran at one particular time. Thus for each query we plan to have a new statement and resultset and close them immediately? Below is given the snippet of code for how we run a query now.We have tried to cover each query with try and catch but the problem if the query fails them the rollback is not working on the global level. How best top put them in place to ensure no memory leak too?
try{ //main try outside
//lots of inner queries run based on some logics of if else etc
//sample query of opening and closing both statement and resultsets.
Statement stmt1 = null;
stmt1 = dbconn.createStatement();
String selectQuery1 = "Select query";
ResultSet rs1 = stmt1 .executeQuery(selectQuery1);
while(rs1.next()) {
//process here
}
try{
if (rs1 != null ){
rs1.close();
}
if (stmt1!= null ){
stmt1.close()
}
}
catch(SQLException ex){
ex.printStackTrace(System.out);
}
dbconn.commit();
}
catch (SQLException ex) {
try {
dbconn.rollback();
}
catch (Exception rollback){
rollback.printStackTrace(System.out);
}
}
catch (Exception e){
try{
dbconn.rollback();
}
catch (Exception rollback) {
rollback.printStackTrace(System.out);
}
}
For rollback to work, you have to first check whether autoCommit is set to false initially. You would want to commit only when all your operations have been executed successfully.
One way of doing this might to use a structure like this:
Connection connection = getDBConnection(); //Depends on how you get your connection
boolean autoCommit = connection.getAutoCommit();
try{
//Set autoCommit to false. You will manage commiting your transaction
connection.setAutoCommit(false);
//Perform your sql operation
if(doCommit){ //all your ops have successfully executed, you can use a flag for this
connection.commit();
}
}catch(Exception exe){
//Rollback
}finally{
connection.setAutoCommit(autoCommit); //Set autoCommit to its initial value
}
Please try keeping dbconn.setAutoCommit(false) as first statement in your first try block so that it will not insert/update/delete query unless you say dbconn.commit()
try{
conn.setAutoCommit(false);
Statement stmt1 = null;
stmt1 = dbconn.createStatement();
String selectQuery1 = "Select query";
ResultSet rs1 = stmt1 .executeQuery(selectQuery1);
while(rs1.next()) {
//process here
}
conn.commit();
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
//Handle errors for JDBC
se.printStackTrace();
try{
if(conn!=null)
conn.rollback();
}catch(SQLException se2){
se2.printStackTrace();
}//end try
}catch(Exception e){
e.printStackTrace();
}finally{
//finally block used to close resources
try{
if(rs!=null)
rs.close();
}catch(SQLException se2){
}// nothing we can do
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}// nothing we can do
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}//end finally try
}//end try
}//
Related
A previous developer left this message in code.
It runs create statement and execute query and after 295 records it creates new connection.
Following is java code:
private void dbUpdate() throws SQLException, Exception {
Statement st = null;
String sql = "";
int count = 0;
try {
getNewConnection();
conn.setAutoCommit(false);
for (Iterator it = sqlList.iterator(); it.hasNext();) {
if (count < 295) { //Closes connection and creates a new one so as not to exceed max cursors
count++;
} else {
st.close();
conn.close();
getNewConnection();
count = 0;
}
sql = (String) it.next();
// System.out.println(sql + " insert count=" + count);
st = conn.createStatement();
try {
st.executeQuery(sql);
} catch(Exception ex) {
Logger.getLogger(LoadMain.class.getName()).log(Level.SEVERE, sql);
Logger.getLogger(LoadMain.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage(), ex);
sb.append("\n").append("Error SQL:" + sql + "|LocalizedMessage:" +ex.getLocalizedMessage());
}
}
} catch (SQLException ex) {
Logger.getLogger(LoadMain.class.getName()).log(Level.INFO, sql);
Logger.getLogger(LoadMain.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage(), ex);
throw new SQLException(ex);
} catch (Exception ex) {
// Logger.getLogger(loadMain.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage(), ex);
throw new Exception(ex);
} finally {
try {
st.close();
conn.close();
} catch (SQLException ex) {
Logger.getLogger(LoadMain.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Is there any logic behind re connection?
(Also developer set autocommit false but not seen committing or roll-backing but only st.close() methods.)
Could anyone please enlighten
Seems as the developer tried to implement connection pooling, which now can be integrated easily with DBCP/Hikari/other database connection pool.
You don't need to commit on DAO level/method, for example
if the code is called by a method with #Transactional or commit is handled on service level.
Also you can't rely that close will commit or rollback, there can be different results with different oracle drivers
According to the javadoc, you should try to either commit or roll back before calling the close method. The results otherwise are implementation-defined.
I have 1 basic program and 1 app, My basic program with this works ( DB_URL, USER, PASS, JDBC_DRIVER all correct and functional) and I am able to get information from my MySQL DB. The code consist of this:
try {
// STEP 2: Register JDBC driver
Class.forName(JDBC_DRIVER);
// STEP 3: Open a connection
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// STEP 4: Execute a query
System.out.println("Creating statement...");
stmt = conn.createStatement();
String sql;
sql = "SELECT distinct tags FROM items";
ResultSet rs = stmt.executeQuery(sql);
// STEP 5: Extract data from result set
while (rs.next()) {
// Retrieve by column name
String itemRoles = rs.getString("tags");
//Add it to the ArrayList.
itemRolesList.add(itemRoles);
// Display values
System.out.print("TAGS: " + itemRoles + "\n");
}
// STEP 6: Clean-up environment
rs.close();
stmt.close();
conn.close();
} catch (SQLException se) {
// Handle errors for JDBC
se.printStackTrace();
} catch (Exception e) {
// Handle errors for Class.forName
e.printStackTrace();
} finally {
// finally block used to close resources
try {
if (stmt != null)
stmt.close();
} catch (SQLException se2) {
}// nothing we can do
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}// end finally try
}// end try
But when I try to apply this same code to my app (inside a Fragment in my OnCreateView()) I get this:
"java.lang.ClassNotFoundException: com.mysql.jdbc.Driver"
and it is at this line of code:
Class.forName(JDBC_DRIVER);
I added the "mysql-connector-java-5.1.23-bin.jar" and it is in my Reference Library in both my program and app. Does anyone know why inside my app it gives me this error?
Make sure that you have driver jar in your classpath.
Please verify that you have jar file inside lib folder is not the empty jar file.sometime during wrong confuguration it shows a empty jar file.
please go to project properties-->buildpath-->libraries
Check out the jar file you have added is not blank.
Consider the following code
ResultSet rs = null;
Statement st = null;
try {
//do somehting
} catch (Exception e){
//do something
} finally {
if(st != null){
try {
st.close();
} catch (SQLException e) {
log.error("Exception while closing statement: " + e);
}
}
}
The question is that when we close the statement, will it close the result set as well or do we need to explicitly close the result set like this
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
log.error("Exception while closing result set: " + e);
}
}
I thought that closing the statement will automatically close the result set, but FindBugs throws the following warning if I don't explicitly close the result set
This method may fail to clean up java.sql.ResultSet
When a Statement object is closed, its current ResultSet object, if one exists, is also closed.
This and this shows that Oracle may have problems and you might have to explicitly close the ResultSet. But again, as per the Javadocs, this shouldn't be an issue. Hence, the warning,maybe.
You can't count on the ResultSet being closed automatically, it depends on the driver implementation and how compliant it is. The best policy is to close the ResultSet explicitly.
When you close the statement or connection, all it's children should be closed too by default.
I have a doubt regarding database operation.I have one insert query that should run for 10 times. the loop starts and inserted 4 or 5 val while inserting 6th, the db connection got failed for a while and again connected. then what will happen,
whether it skips that particular val or throws exception or roll back th entire operation?
EDIT : Sample Code
try
{
String sql_ji_inser="insert into job_input values (?,?)";
PreparedStatement pst_ji_inser=OPConnect.prepareStatement(sql_ji_inser);
for(int i=0;i<v_new_data.size();i++)
{
Vector row=new Vector();
row=(Vector)v_new_data.get(i);
job_id=Integer.parseInt(row.get(0).toString());
item_no=Integer.parseInt(row.get(1).toString());
pst_ji_inser.setInt(1,job_id);
pst_ji_inser.setInt(2,item_no);
pst_ji_inser.addBatch();
}
System.out.println("No of rows inserted"+pst_ji_inser.executeBatch().length);
}
catch(Exception ex)
{
System.out.println("********Insert Exception*********************");
ex.printStackTrace();
return false;
}
Is this the right way
try
{
int count=0;// for checking no of inserting values
OPConnect.setAutoCommit(false);
String sql_ji_inser="insert into job_input values (?,?)";
PreparedStatement pst_ji_inser=OPConnect.prepareStatement(sql_ji_inser);
for(int i=0;i<v_new_data.size();i++)
{
job_id=Integer.parseInt(row.get(0).toString());
item_no=Integer.parseInt(row.get(1).toString());
pst_ji_inser.setInt(1,job_id);
pst_ji_inser.setInt(2,item_no);
pst_ji_inser.addBatch();
count++;
}
int norowinserted=pst_ji_inser.executeBatch().length;
if(count==norowinserted)
{
OPConnect.commit();
}
}
catch(Exception ex)
{
System.out.println("********Insert Exception*********************");
OPConnect.rollback();
ex.printStackTrace();
return false;
}
That depends on how you're inserting the rows. If you're inserting them in a single transaction on a connection which has auto-commit turned off by connection.setAutoCommit(false) and you're commiting the connection after completing the insert queries using connection.commit() and you're explicitly calling connection.rollback() inside the catch block, then the entire transaction will be rolled back. Otherwise, you're dependent on environmental factors you have no control over.
See also:
When to call rollback?
Update: here's a rewrite of your code. Note that the connection and statement should be declared before the try, acquired in the try and closed in the finally. This is to prevent resource leaking in case of exceptions.
String sql = "insert into job_input values (?, ?)";
Connection connection = null;
PreparedStatement statement = null;
try {
connection = database.getConnection();
connection.setAutoCommit(false);
statement = connection.prepareStatement(sql);
for (List row : data) {
statement.setInt(1, Integer.parseInt(row.get(0).toString()));
statement.setInt(2, Integer.parseInt(row.get(1).toString()));
statement.addBatch();
}
statement.executeBatch();
connection.commit();
return true;
} catch (SQLException e) {
if (connection != null) try { connection.rollback(); } catch (SQLException logOrIgnore) {}
e.printStackTrace();
return false;
} finally {
if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
}
I am by the way not a fan of returning a boolean here. I'd just make the method void, let the catch throw e and put the calling code in a try-catch.
I ran findbugs on our code base and it pointed out there are two more Statements that still need to be closed. In this section of the code we run:
preparedStatement = connection.prepareStatement(query);
for 3 different queries, reusing preparedStatement. In the finally block we do close the resource:
finally{
try{
if (resultSet != null)
resultSet.close();
} catch (Exception e) {
exceptionHandler.ignore(e);
}
try {
if (preparedStatement != null)
preparedStatement.close();
} catch(Exception e) {
exceptionHandler.ignore(e);
}
Should the statement be closed before the next connection.prepareStatement(query); or is this findbugs being cautious?
Yes, the statement must be closed before you perform the next connection.prepareStatement. Otherwise, you're losing your reference to the un-closed previous one (aka leaking statements). Wrap a try {} finally {} around each statement use, closing it in the finally.