I have a DAO class with many methods that have a lot of repeated code along the lines of: -
public void method1(...) {
Connection conn = null;
try {
//custom code here
} catch (SQLException e) {
LOG.error("Error accessi开发者_如何学编程ng the database.", e);
throw new DatabaseException();
} catch (QueryNotFoundException e) {
LOG.error("Error accessing the database.", e);
throw new DatabaseException();
} finally {
if (conn != null)
connectionPool.returnConnection(conn);
}
public void method2(...) {
Connection conn = null;
try {
//different custom code here
} catch (SQLException e) {
LOG.error("Error accessing the database.", e);
throw new DatabaseException();
} catch (QueryNotFoundException e) {
LOG.error("Error accessing the database.", e);
throw new DatabaseException();
} finally {
if (conn != null)
connectionPool.returnConnection(conn);
}
I would like to restructure this class to put the try, catch, finally in one place to avoid repetation. How would I accomplish this?
Create an interface for ex. Executable:
public interface Executable() {
void exec() throws SqlException();
}
Refactor each of your dao method to :
public void method1() {
execute(new Executable() {
@Override
public void exec() throws SqlException() {
// your code here
}
});
}
Create the following method execute in your DAO:
private void execute(Executor ex) {
try {
ex.exec();
} catch(...) {
...
} finally {
...
}
}
I think what you should use is Spring-JDBC's JdbcTemplate
Even if you don't use spring to manage your application, you could programmatically use JdbcTemplate to abstract away all the connection management and error handling.
Example code:
List<Actor> actors = this.jdbcTemplate.query(
"select first_name, last_name from t_actor",
new RowMapper<Actor>() {
public Actor mapRow(ResultSet rs, int rowNum)
throws SQLException {
Actor actor = new Actor();
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
return actor;
}
});
As you can see, you deal with the actual query only, not with the infrastructure stuff around it.
I would use AOP for a commong logging pattern here. For example:-
<bean id="exceptionLogger" class="my.good.ExceptionLogger" />
<aop:config>
<aop:pointcut id="allDaoMethods" expression="execution(* my.dao.*(..))" />
<aop:aspect id="daoLogger" ref="exceptionLogger">
<aop:after-throwing pointcut-ref="allDaoMethods"
method="logIt"
throwing="e"/>
</aop:aspect>
</aop:config>
And the ExceptionLogger class could be something like below:-
public class ExceptionLogger {
private static Logger logger = Logger.getLogger(ExceptionLogger.class);
public void logIt(JoinPoint jp, Exception e) {
StringBuilder msg = new StringBuilder();
msg.append("<whatever makes sense>");
logger.error(msg.toString());
}
}
This is similiar to Vladimirs solution without anonymous classes with possibility to return value from such methods.
interface DaoOperation {
void execute() throws SQLException;
}
class Operation1 implements DaoOperation {
public void execute() {
// former method1
}
}
// in case you'd ever like to return value
interface TypedDaoOperation<T> {
T execute() throws SQLException;
}
class Operation2 implements TypedDaoOperation<String> {
public String execute() {
return "something";
}
}
class DaoOperationExecutor {
public void execute(DaoOperation o) {
try {
o.execute();
} catch (SQLException e) {
// handle it as you want
}
}
public <T>T execute(TypedDaoOperation<T> o) {
try {
return o.execute();
} catch (SQLException e) {
// handle it as you want
}
}
}
精彩评论