Invoke method in another class's try catch block - java

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

Related

SQL connections dangling: Where am I not correctly closing up connections correctly?

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");
}

The static method getDBConnection() from the type DBConnection should be accessed in a static way

I have got a singleton class as shown below for accessing Database connection as
public class DBConnection {
private static volatile DBConnection instance;
private static DataSource dataSource;
private DBConnection(){
}
public static synchronized DBConnection getInstance() {
if (instance == null) {
instance = new DBConnection();
}
return instance;
}
static {
try {
dataSource = (DataSource) new InitialContext()
.lookup("java:comp/env/jdbc/MySQLDataSource");
} catch (NamingException e) {
e.printStackTrace();
try {
throw new Exception("'jndifordbconc' not found in JNDI", e);
} catch (Exception e1) {
logger.error("Error description", e);
}
}
}
public static Connection getDBConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
logger.error("Error description", e);
return null;
}
}
}
And when i am trying to access the DBConnection this way
SeperateClass
Here i am getting the yellow warning
public String fetchGlobalIndicesData(#QueryParam("region_name") String region_name )
{
Connection dbConnection = null;
String selectsql = "";
try
{
dbConnection = DBConnection.getInstance().getDBConnection();
selectpstmt = dbConnection.prepareStatement(selectsql);
selectpstmt.setString(1, region_name);
selectRset = selectpstmt.executeQuery();
}
catch (Exception e)
{
logger.error("Error description",e);
}
}
Eclipse IDE is giving me a yellow warning saying
The static method getDBConnection() from the type DBConnection should be accessed in a static way
Could you please tell me whats the proper way of doing this ??
I modified my code as
public static Connection getDBConnection() {
try {
return getInstance().dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
logger.error("Error description", e);
return null;
}
}
Since it is static, you are supposed to call the method directly on the class , not on an instance of the class :
DBConnection.getDBConnection()
Calling the method on an instance has no sense, though it is possible.
As #Berger mentioned, you defined the method as static, so you have to call it as he mentioned.
If you don't want it static, you can modify your code by removing static from the getDBConnection method and call it as:
DBConnection.getInstance().getDBConnection()
The code above is already correct in your fetchGlobalIndicesData method.
Just for the sake of it:
public static Connection getDBConnection()
Becomes:
public Connection getDBConnection()
This way, getInstance will initialize a DBConnection instance, and the static initializer block to init your datasource should fire. Then when you call getDBConnection, your code should work fine.
That is an static method, you can remove the static keyword of the getDBConnection() signature or use DBConnection.getDBConnection()

Java - Design Pattern for repeating sql tasks

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.

I cannot extend the class in java

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()

Problem in data insertion in Ms access..But Code runs fine

import java.sql.*;
// I think this is a poor abstraction
public class NewConnection {
/*very important: dont use statics for your Connection, Statement and Query objects,
since they can and will be overriden by other Instances of your NewConnection.*/
// There's no need at all for having class members here. It's actually
// a terrible idea, because none of these classes are thread-safe.
private Connection con;
private ResultSet rs;
private Statement sm;
// Better to pass these in.
private final String DRIVER = "sun.jdbc.odbc.JdbcOdbcDriver";
private final String URL = "jdbc:odbc:Driver={Microsoft Access driver (*.mdb)};DBQ=E:\\db1.mdb;DriverID=22";
// private final String URL = "jdbc.odbc.Cooper_Dsn1";
// Another poor idea. Why not just pass this in to the query method?
private static String query;
int i;
private void getConnection(){
try {
Class.forName(DRIVER);
}
catch(ClassNotFoundException e)
// Less information that printing the stack trace.
{System.out.println("Error ="+e);}
try{
System.out.println("Driver Connected");
con=DriverManager.getConnection(URL,"","");
System.out.println("Database Connected");
sm=con.createStatement();
}catch(SQLException e){
System.out.println(e.getMessage());
}
}
// lower case "execute" is the Java convention
private int ExecuteUpdate(String query1)
{ try{
System.out.println(query1);
i=sm.executeUpdate(query1);
con.commit();
}catch(SQLException e){
// No rollback in the event of a failure
System.out.println(e.getMessage());
}
return i;
}
public int executeUpdate(String sql) throws SQLException
{
System.out.println(sql);
con.commit(); // What's this doing? Incorrect
return sm.executeUpdate(sql);
}
// Here's how I might write an update method.
public static int update(Connection connection, String sql)
{
assert connection != null && sql != null;
int numRowsAffected = 0;
PreparedStatement ps = null;
connection.setAutoCommit(false);
try
{
numRowsAffected = ps.execute(sql);
connection.commit();
}
catch (SQLException e)
{
e.printStackTrace();
DatabaseUtils.rollback(connection); // Add this method.
numRowsAffected = 0;
}
finally
{
DatabaseUtils.close(ps);
}
return numRowsAffected;
}
public static void main(String []args) throws SQLException{
NewConnection n= new NewConnection();
n.getConnection();
query="insert into Employee(empid,ename,ephone,email) values('samr','sam','sa','aas');";
System.out.println(n.ExecuteUpdate(query));
}
}
I had modified the code to this....but still has no effect... The query runs successfully but doesn't add data in database. Don't know y..? The code creates the table in database successfully if query changed.
Can any one tell me what is the problem Or Where i m wrong..
You won't see any INSERT with Access until you close your Connection properly.
Your code doesn't close any resources, which will surely bring you grief. Call the close methods in reverse order in a finally block.
public class DatabaseUtils
{
public static Connection createConnection(String driver, String url, String username, String password)
throws ClassNotFoundException, SQLException
{
Class.forName(driver);
return DriverManager.getConnection(url, username, password);
}
public static void close(Connection connection)
{
try
{
if (connection != null)
{
connection.close();
}
}
catch (SQLException e)
{
e.printStackTrace(e);
}
}
public static void close(Statement statement)
{
try
{
if (statement != null)
{
statement.close();
}
}
catch (SQLException e)
{
e.printStackTrace(e);
}
}
public static void close(ResultSet rs)
{
try
{
if (rs != null)
{
rs.close();
}
}
catch (SQLException e)
{
e.printStackTrace(e);
}
}
}

Categories