I have different methods, which queries different data from a database, but the main structure of every method is the same. To reduce the code, I want to shrink that but I don't know how. I have tried interfaces but the return statement cannot called from an inner class. (It should be typesafe!)
Structure:
public <special type> getXYdata(some parameters) {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(... special query ...)
) {
// Handle ResultsSet and return object of a special type.
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
Idea:
private interface QHandler<T> {
String getQuery();
T handleResultSet(ResultSet set) throws SQLException;
}
And then:
private void executeQuery(QHandler handler) throws ContentManagerException {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(handler.getQuery())
) {
handler.handleResultSet(results);
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
But if I call this private method in one of my data mathods, I cannot return an object from the handleResultSet() methods, because the return statement will affect this interface method. Is there an option, to tell the execiteQuery() method which return type the handler has?
Attention: It has to be type safe, no casting if possible!
Your method should not use a raw QHandler type, and should be generic:
private <T> T executeQuery(QHandler<T> handler) throws ContentManagerException {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(handler.getQuery())
) {
return handler.handleResultSet(results);
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
Note that you're trying to reinvent Spring's JdbcTemplate. You might consider using it instead of reinventing it.
Maybe you are open for alternative solutions. If you are using Java 8, you can do somehting like this:
Interface MyHandler {
<T> T handle(Connection c);
}
class MyHelperClass {
public <T> T withConnection(MyHandler handler) {
try {
Connection connection = mDataSource.getConnection();
return handler.handle(connection);
} catch (...) {
...
} finally {
...
}
}
}
Usage:
Result r = myHelperObject.withConnection(con -> {
ResultSet results = connection.createStatement().executeQuery(query)
return new Result(..)
});
This way you can use lambda expressions so you do not need to implement various new classes for your handler interface.
Related
I am building a basic java application to load some files into a mysql database. I am able to load the files up and populate my tables without any problems. However after speaking to someone who reviewed my code, I am apparently not correctly closing my connections and wasting resources. Where am I not closing up the connections? Have I done this incorrectly?
I am using the try-with-resources construct within my DbSinger class to execute prepared statements to my database, which should automatically close the connection so long as the AutoCloseable interface is implemented, which it is in the parent class of Db. The close() method however is never reached. The DbSinger is instantiated inside my main() and then runs it's single method populateSingers() with an ArrayList of Singer objects.
Connection Class
public class SQLConnection {
private static final String servername = "localhost";
private static final int port = 3306;
private static final String user = "ng_user";
private static final String pass = "ng";
private static final String db = "ng_music";
private static final String connectionString = "jdbc:mysql://" + servername + ":" + port + "/" + db;
public Connection provide() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(connectionString, user, pass);
}
catch (SQLException | ClassNotFoundException e) {
throw new SQLConnectionException(e);
}
}
public class SQLConnectionException extends RuntimeException {
SQLConnectionException(Exception e) {super(e);}
}
}
Abstract parent class
public abstract class Db implements AutoCloseable{
private Connection connection;
Db() {
SQLConnection sqlC = new SQLConnection();
this.connection = sqlC.provide();
}
#Override
public synchronized void close() throws SQLException {
if(connection != null) {
connection.close();
connection = null;
System.out.println("Connection closed");
}
}
Connection getConnection() {
return connection;
}
boolean checkIfPopulated(String query){
try {
PreparedStatement ps = getConnection().prepareStatement(query);
ResultSet rs = ps.executeQuery();
return !rs.next();
} catch (SQLException e) {
e.printStackTrace();
}
return true;
}
}
Concrete class to execute queries to database for singers table
public class DbSinger extends Db {
public DbSinger() {
super();
}
public void populateSingers(ArrayList<Singer> singers) {
String populateSingersQuery = "insert into ng_singers(name, dob, sex) values(?,?,?)";
if(!checkIfPopulated("select * from ng_singers")){
System.out.println("Singer Table is already populated");
return;
}
try (PreparedStatement ps = getConnection().prepareStatement(populateSingersQuery)) {
for (Singer s : singers) {
ps.setString(1, s.getName());
ps.setDate(2, java.sql.Date.valueOf(s.getDob()));
ps.setString(3, s.getSex());
ps.addBatch();
}
ps.executeBatch();
System.out.println("Singers added to table");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
My code is able to execute is able to run fine and does what it needs to, but I want to understand why and where I am not closing connections, and to understand how I can resolve this. Or at least understand if I am approaching this wrong.
In your case, you need to instantiate DBSinger class in try-with-resources statement to close the underlying connection.
Instead of doing:
DbSinger dbSinger = new DbSinger();
You need to do:
try (DbSinger dbSinger = new DbSinger()) {
// Your other code
}
This way the close() method you are overriding in your Db class will be called automatically.
Also, close the preparedStatement you created in your checkIfPopulated method by:
try (PreparedStatement ps = getConnection().prepareStatement(query)) {
// Other codes
}
Your code is old way. And you do need close manually. However, with Java 8, you can use try with resource like below,
try (Connection conn = ds.getConnection();
Statement stmt = conn.createStatement()) {
try {
stmt.execute(dropsql);
} catch (Exception ignore) {} // ignore if table not dropped
stmt.execute(createsql);
stmt.execute(insertsql);
try (ResultSet rs = stmt.executeQuery(selectsql)) {
rs.next();
} catch (Exception e2) {
e2.printStackTrace();
return("failed");
}
} catch(Exception e) {
e.printStackTrace();
return("failed");
}
I have some methods that follow this pattern
try(Connection connection = MySqlConnection.getConnection()){
PreparedStatement statement = connection.prepareStatement(
"Insert into db values (NULL ,?,?,?,?,?, NULL , ?)",
Statement.RETURN_GENERATED_KEYS);
...
statement.executeUpdate();
...
}
catch(SQLException e) {
throw new RuntimeException(e);
}
I was told to extract try-catch with connection to class MySqlConnection and create a new method that would execute all logic and encapsulate creating connection. So, I don't quite get this approach and have no idea, how to resolve it without writing some ugly templates or strategies. Would it be better to just leave it as it is, or can it be implemented in an easy way?
Create a ConnectionHelper that will deal with exceptions. This is a little bit tricky, you have to define your own functional interface because standard Consumer does not work with checked SQLExceptions:
public class ConnectionHelper {
#FunctionalInterface
public interface ConnectionConsumer {
void accept(Connection connection) throws SQLException;
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Then use it like this:
public void doSomeUpdate() {
ConnectionHelper.doWithConnection(connection -> {
PreparedStatement statement = connection.prepareStatement(
"Insert into db values (NULL ,?,?,?,?,?, NULL , ?)",
Statement.RETURN_GENERATED_KEYS);
statement.executeUpdate();
});
}
This works well as long as you don't have to return anything from your database, which is rarely the case. So we need to extend the helper with another functional interface, ConnectionFunction, to be used when an object needs to be returned:
public class ConnectionHelper {
#FunctionalInterface
public interface ConnectionConsumer {
void accept(Connection connection) throws SQLException;
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
...
}
#FunctionalInterface
public interface ConnectionFunction<T> {
T apply(Connection connection) throws SQLException;
}
public static <T> T doWithConnection(ConnectionFunction<T> connectionFunction) {
try (Connection connection = MySqlConnection.getConnection()) {
return connectionFunction.apply(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Then use it like this:
public boolean doSomeQuery() {
return ConnectionHelper.doWithConnection(connection -> {
PreparedStatement statement = connection.prepareStatement("SELECT * FROM table");
return statement.execute();
});
}
Updates
2 solutions to work with SQLIntegrityConstraintViolationException:
Own, runtime exception:
As this is a runtime exception, you just add try-catch where needed.
public static class MySQLIntegrityConstraintViolationException extends RuntimeException {
public MySQLIntegrityConstraintViolationException(Throwable cause) {
super(cause);
}
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLIntegrityConstraintViolationException e) {
throw new MySQLIntegrityConstraintViolationException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
insertWithConnection:
A specialized version of doWithConnection(). Again, use it only where/when applicable.
public static void insertWithConnection(ConnectionConsumer connectionConsumer) throws SQLIntegrityConstraintViolationException {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLIntegrityConstraintViolationException e) {
throw e;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
Use java functional interface to separate exception handling from business logic, like this:
public class ExceptionHandler() {
public R execute(Function<T,R> function, T argument) {
try {
return function.apply(argument)
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Now you can pass to the class above any function that will contain your logic and handling exception will be independent.
Furthermore, this way you can create many useful methods, and classes that work like a proxy, or which are needed for every operation, and hat will be independent of your business logic.
For example, in the same way, you can write:
your own transaction management,
logging input and output
check user and permissions
and any other interceptor
I have a code section like bellow:
try (UnitOfWork unitOfWork = datasource.getConnection()) {
ResultSet resultset = untiOfWork.getStatement().getResultSet();
unitOfWork.queueToClose(resultSet);
...
}
The UnitOfWork is an AutoClosable. So inside of the UnitOfWork close() method is like this.
#Overide
public void close() {
for (AutoClosable closable : queueToClose) {
closable.close();
}
connection.close();
}
Now the FindBug is complaining about the ResultSet is not being closed. Is this a false positive? Is this a bad pattern?
In addition to the excellent answer that 'Alexey Romanov' posted there is a potential leak in your implementation of UnitOfWork.close where if any of those close calls throws an exception your connection is not closed.
#Override
public void close() throws Exception {
Exception first = null;
try (AutoCloseable requiredForJdk8 = this.connection) {
for (AutoCloseable closable : this.queueToClose) {
try {
closable.close();
} catch (Exception e) {
if (first == null) {
first = e;
} else {
if (first != e) {
first.addSuppressed(e);
}
}
}
}
if (first != null){
throw first;
}
}
}
It is a false positive in the sense that ResultSet will be closed, but there is no way for FindBugs to know this.
It is also a bad pattern: what happens if you forget to call queueToClose after getting a ResultSet? Does UnitOfWork.getStatement() add the statement to queueToClose before returning it?
Better would be
try (UnitOfWork unitOfWork = datasource.getConnection();
Statement statement = unitOfWork.getStatement();
ResultSet resultset = statement.getResultSet()) {
...
}
This is may one class.
Now i want to create a new class registrationvalidator extending LoginValidator.
i tried by
public class registrationvalidator extends LoginValidator {
}
But its show error in netbeans...What is the soluation?
public LoginValidator() throws SQLException{
try {
connect = new Dbconnect();
st = connect.Statement();
} catch (SQLException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int validator(String mobileNo,String pass){
int ret = 0;
try{
String query="select * from login where mobileNo='"+mobileNo+"'";
res= st.executeQuery(query);
while(res.next()){
String dbMobileNo=res.getString("mobileNo");
String dbPass=res.getString("password");
if(mobileNo.equals(dbMobileNo) && pass.equals(dbPass)){
ret=1;
}
else if(mobileNo.equals(dbMobileNo)){
ret=2;
}
}
}catch(SQLException ex){
System.out.println("Sql Execption: "+ex);
System.out.println("3");
}
return ret;
}
}
A few things here.
You can only define one public class per java file. So your RegistrationValidator class should be in its own java file, separate from the LoginValidator class.
Since you are catching the SQLException and logging some info, you don't need the "throws SQLException" for the constructor signature LoginValidator()
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Here is my story. I have myCon=getUnusedConnection(); method that get a connection from Connection pool. I also have a releaseConnection(myCon); method to release Connection to the pool after finishing using it.
Ok, When coding, I need to select data from Database many times & cos I wanna reuse my code so I wanna have many methods for 1 single Action. Ex,
public static List<String[]> getData(){
Connection myCon=null;
PreparedStatement preparedStmt=null;
try{
myCon=getUnusedConnection();
String sql="select ........";
preparedStmt=myCon.prepareStatement(sql);
ResultSet results=preparedStmt.executeQuery();
String str="";
if(results.next()){
str=results.getString(1);
}
if(!str.equals("")){
List<String[]> list=getData2(myCon, preparedStmt, str);
}
return list;
}
catch (SQLException ex) {
while (ex != null) {
System.out.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
}catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
}
finally{
releaseConnection (myCon);
closeStatement (preparedStmt);
}
return null;
}
public static List<String[]> getData2(Connection myCon, PreparedStatement preparedStmt, String str){
try{
List<String[]> list=new ArrayList<String[]>();
String sql="c.......";
preparedStmt=myCon.prepareStatement(sql);
ResultSet results=preparedStmt.executeQuery();
while(results.next()){
list.add(results.getString(1));
}
return list;
}catch (SQLException ex) {
while (ex != null) {
System.out.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
}catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
}
finally {
closeStatement(preparedStmt);
releaseConnection(myCon);
}
return null;
}
Do i need to include try - catch - finally in getData2?
Since I am passing myCon & prepareStatement around so I am not sure is this the right way to code.
Is it a standard way for what I am coding? or do u do better coding?
Do i need to include try - catch - finally in getData2?
The answer depends on other places from which you call getData2:
If getData is the only place, then the answer is "no", a try/finally would be sufficient.
If there are other places all of which expect a SQLException and process it in the same way, the answer is also "no", for the same reason (no catch is required).
If there are other places, some of which do not expect SQLException, then you need to keep the try - catch - finally
However, there is a problem with the way that you coded your call of getData2: since getData2 has a finally that releases the connection, your getData releases the connection twice. You need to either add a useExistingConnection(conn) and modify your releaseConnection in a way to count references to the same connection, or pass a flag that indicates whether or not the connection should be closed.
Generally, I would prefer to structure the code to open and close the connection in the same method, pass the connection around to other methods, and use try/finally only to close the PreparedStatements opened inside subordinate methods, such as getData2.
I'd made your method getData2() private and not catching (if it handle the exception same as parent) and closing resources in finally if you do in top level. If you can't change it, make another method private for example getData3() without try-catch-finally.
However i'd made another change, if all of your methods follow the same template.
The callable interface for calling.
public interface Queryable<T>{
T execute();
}
Then the util class.
public final class SQLUtil {
private SQLUtil() { }
public static Connection getConnection() {
return getUnusedConnection();
}
public <T> static T query(Queryable queryable) {
T toReturn = null;
try {
toReturn = queryable.execute();
} catch (SQLException ex) {
while (ex != null) {
System.err.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
} catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
} finally {
releaseConnection (myCon);
closeStatement (preparedStmt);
}
}
//add code for getUnusedConnection, releaseConnection, closeStatement
}
And yor client code will look like this:
public List<String[]> getData(){
return SQLUtil.query(new Queryable<List<String[]>>() {
#Override
public List<String[]> execute() {
Connection myCon=getUnusedConnection();
String sql="select ........";
PreparedStatement preparedStmt=myCon.prepareStatement(sql);
ResultSet results=preparedStmt.executeQuery();
String str="";
if(results.next()) {
str=results.getString(1);
}
List<String[]> list = null;
if(!str.equals("")) {
list=getData2(myCon, preparedStmt, str);
}
return list;
}
});
}