Nested try-with-resources vs single - java

So I came across some code and wondered what would be the difference between using nested try-with-resource statements and using a single try-with-resource with multiple resources?
private void doEverythingInOneSillyMethod(String key)
throws MyAppException
{
try (Connection db = ds.getConnection()) {
db.setReadOnly(true);
...
try (PreparedStatement ps = db.prepareStatement(...)) {
ps.setString(1, key);
...
try (ResultSet rs = ps.executeQuery()) {
...
}
}
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
vs:
private void doEverythingInOneSillyMethod(String key)
throws MyAppException {
try (Connection db = ds.getConnection();
PreparedStatement ps = db.prepareStatement(...);
ResultSet rs = ps.executeQuery();) {
db.setReadOnly(true);
ps.setString(1, key);
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
are there any benefits with the former?

Related

How to Close Statements and Connection in This Method

How to Close Statements and Connection in This Method
public static ResultSet getData (String query){
try {
Connection con = ConnectionProvider.connect();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
return rs;
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
System.out.println(e);
return null;
}
You need to close connections in finally block:
try {
...
}
catch {
...
}
finally {
try { st.close(); } catch (Exception e) { /* Ignored */ }
try { con.close(); } catch (Exception e) { /* Ignored */ }
}
In Java 7 and higher you can define all your connections and statements as a part of try block:
try(Connection con = ConnectionProvider.connect();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
) {
// Statements
}
catch(....){}
One should use try-with-resources to automatically close all.
Then there is the p
public static void processData (String query, Consumer<ResultSet> processor){
try (Connection con = ConnectionProvider.connect();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query)) {
processor.accept(rs);
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, e);
System.getLogger(getClass().getName()).log(Level.Error, e);
}
}
processData("SELECT * FROM USERS", rs -> System.out.println(rs.getString("NAME")));
Or
public static <T> List<T> getData (String query, UnaryOperator<ResultSet, T> convert){
try (Connection con = ConnectionProvider.connect();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query)) {
List<T> result = new ArrayList<>();
while (rs.next()) {
result.add(convert.apply(rs));
}
return result;
} catch (SQLException e) {
System.getLogger(getClass().getName()).log(Level.Error, e);
throw new IllegalArgumentException("Error in " + query, e);
}
}
Then there is the danger with this function, that users will compose query strings like:
String query = "SELECT * FROM USERS WHERE NAME = '" + name + "'";
Which does not escape the apostrophes like in d'Alembert. It opens the gates to SQL injection, a large security breach. One needs a PreparedStatement, and then can use type-safe parameters.
As with try-with-resources the code already is reduced (no explicit closes), you should drop this kind of function. But almost most programmers make this mistake.

SQL query in Java does not work, no error is appearing but the data isn't appearung in DB

I try to insert a row to the database, but it doesn't appear in the table after running:
This is the main class:
public class Tester {
public static void main(String[] args) {
CouponsDbDao coupDbDao = new CouponsDbDao();
Coupon coupon = new Coupon(1, 0, Category.Food, null, null, null, null, 25, 0, null);
coupDbDao.addCoupon(coupon);
}
}
And this is the method:
public class CouponsDbDao {
public void addCoupon(Coupon coupon) {
try {
Connection connection = JdbcUtils.getConnection();
String sqlStatement = "insert into coupons (COMPANY_ID,CATEGORY_ID,TITLE,DESCRIPTION,START_DATE,END_DATE,AMOUNT,PRICE,IMAGE) values(?,?,?,?,?,?,?,?,?)";
PreparedStatement statement = connection.prepareStatement(sqlStatement);
statement.setInt(1, coupon.getCompanyId());
statement.setObject(2, coupon.getCategory());
statement.setString(3, coupon.getTitle());
statement.setString(4, coupon.getDescription());
statement.setDate(5, coupon.getStartDate());
statement.setDate(6, coupon.getEndDate());
statement.setInt(7, coupon.getAmount());
statement.setDouble(8, coupon.getPrice());
statement.setString(9, coupon.getImage());
} catch (Exception e) {
e.printStackTrace();
}
}
You need to execute the statement after setting values. Additionally, you need to close the connection created, the preparedstatement etc in a finally block.
public class CouponsDbDao {
Connection connection = null;
PreparedStatement statement = null;
public void addCoupon(Coupon coupon) {
try {
connection= JdbcUtils.getConnection();
String sqlStatement = "insert into coupons (COMPANY_ID,CATEGORY_ID,TITLE,DESCRIPTION,START_DATE,END_DATE,AMOUNT,PRICE,IMAGE) values(?,?,?,?,?,?,?,?,?)";
statement = connection.prepareStatement(sqlStatement);
statement.setInt(1, coupon.getCompanyId());
statement.setObject(2, coupon.getCategory());
statement.setString(3, coupon.getTitle());
statement.setString(4, coupon.getDescription());
statement.setDate(5, coupon.getStartDate());
statement.setDate(6, coupon.getEndDate());
statement.setInt(7, coupon.getAmount());
statement.setDouble(8, coupon.getPrice());
statement.setString(9, coupon.getImage());
statement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
finally{
if (statement != null) {
try {
statement.close();
} catch (SQLException e) { /* print here */}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) { /* print here */}
}
}
}
As told by others you need to call executeUpdate to really perform the query:
Executes the SQL statement in this PreparedStatement object, which must be an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or DELETE
I suggest you also to use the try with resources:
The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.
This has been introduced in java 7 and let you eliminate the finally boiler plate code as follow:
// ORIGINAL CODE
Connection connection = ...
try {
connection = JdbcUtils.getConnection();
...
statement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) { /* print here */}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) { /* print here */}
}
}
becomes:
// USING try with resources
try (Connection connection = JdbcUtils.getConnection()) {
...
statement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} // NO need of the finally block because connection is AutoCloseable
You need to execute update for statement, like:
statement.executeUpdate();

Statement Leakage in JDBC

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) {
}
}
}

How to run methods inside a standard try catch

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)

Handling all exceptions when executing SQL in Java

There are many steps involved in executing one SQL statement in Java:
Create connection
Create statement
Execute statement, create resultset
Close resultset
Close statement
Close connection
At each of these steps SQLException can be thrown. If we to handle all exception and release all the resources correctly, the code will will look like this with 4 levels of TRY stacked on the top of each other.
try {
Connection connection = dataSource.getConnection();
try {
PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM myTable");
try {
ResultSet result = statement.executeQuery();
try {
if (result.next()) {
Integer theOne = result.getInt(1);
}
}
finally {
result.close();
}
}
finally {
statement.close();
}
}
finally {
connection.close();
}
}
catch (SQLException e) {
// Handle exception
}
Can you propose a better (shorter) way to execute a statement while still release all the consumed resources?
If you are using Java 7, the try with resources statement will shorten this quite a bit, and make it more maintainable:
try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(queryString); ResultSet rs = ps.execute()) {
} catch (SQLException e) {
//Log the error somehow
}
Note that closing the connection closes all associated Statements and ResultSets.
Check out Apache Commons DbUtils, and in particular the closeQuietly() method. It will handle the connection/statement/result set closing correctly, including the cases where one or more are null.
An alternative is Spring JdbcTemplate, which abstracts a lot of work away from you, and you handle your database queries in a much more functional fashion. You simply provide a class as a callback to be called on for every row of a ResultSet. It'll handle iteration, exception handling and the correct closing of resources.
I create a utility class with static methods I can call:
package persistence;
// add imports.
public final class DatabaseUtils {
// similar for the others Connection and Statement
public static void close(ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (Exception e) {
LOGGER.error("Failed to close ResultSet", e);
}
}
}
So your code would be:
Integer theOne = null;
Connection connection = null;
PreparedStatement statment = null;
ResultSet result = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
while (result.next()) {
theOne = result.getInt(1);
}
} catch (SQLException e) {
// do something
} finally {
DatabaseUtils.close(result);
DatabaseUtils.close(statement);
DatabaseUtils.close(connection);
}
return theOne;
I'd recommend instantiating the Connection outside this method and passing it in. You can handle transactions better that way.
Connection connection = null;
PreparedStatement statement = null;
ResultSet result = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
if (result.next()) {
Integer theOne = result.getInt(1);
}
}
catch (SQLException e) { /* log error */ }
finally {
if (result != null) try { result.close(); } catch (Exception e) {/*log error or ignore*/}
if (statement != null) try { statement.close(); } catch (Exception e) {/*log error or ignore*/}
if (connection != null) try { connection.close(); } catch (Exception e) {/*log error or ignore*/}
}
Just close the Connection, this releases all resources*. You don't need to close Statement and ResultSet.
*just make sure you don't have any active transactions.
Your code can be shortened and written in this way...
Connection connection = dataSource.getConnection();
PreparedStatement statement = null;
ResultSet result = null;
try {
statement= connection.prepareStatement("SELECT 1 FROM myTable");
result = statement.executeQuery();
if (result.next()) {
Integer theOne = result.getInt(1);
}
} catch (SQLException e) {
// Handle exception
} finally {
if(result != null) result.close();
if(statement != null) statement.close();
if(connection != null) connection.close();
}

Categories