Java 从 DAO 中移除重复的 try、catch、finally 样板

Posted

技术标签:

【中文标题】Java 从 DAO 中移除重复的 try、catch、finally 样板【英文标题】:Java Remove repeated try, catch, finally boilerplate from DAO 【发布时间】:2011-05-26 11:44:35 【问题描述】:

我有一个 DAO 类,其中包含许多重复代码,如下所示:-

public void method1(...) 
  Connection conn = null;
  try 
      //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);
   

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

我想重组这个类,将 try、catch、finally 放在一个地方以避免重复。我将如何做到这一点?

【问题讨论】:

【参考方案1】:

为 ex 创建一个接口。可执行文件:

 public interface Executable() 

   void exec() throws SqlException();

 

将每个 dao 方法重构为:

public void method1() 
   execute(new Executable() 

     @Override
     public void exec() throws SqlException() 
          // your code here
     
  );
   

在你的 DAO 中创建以下方法执行:

private void execute(Executor ex) 
    try 
      ex.exec();
     catch(...) 
      ...
     finally 
       ...
    

【讨论】:

是的,如果 JdbcTemplate 不是一个选项(+1),那是我要建议的下一个模式【参考方案2】:

我认为你应该使用Spring-JDBC的JdbcTemplate

即使您不使用 spring 来管理您的应用程序,您也可以通过编程方式使用 JdbcTemplate 来抽象出所有连接管理和错误处理。

示例代码:

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

如您所见,您只处理实际查询,而不是处理它周围的基础设施。

【讨论】:

【参考方案3】:

我会在这里使用AOP 作为commong 日志记录模式。例如:-

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

ExceptionLogger 类可能如下所示:-

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

【讨论】:

这对我来说很有趣。你能解释更多吗?我也是这种情况 您希望我详细解释哪一部分?您可以在我提供的链接上阅读有关 AOP 的信息。我还给出了 aop 配置和示例异常类的示例。 这也是基于弹簧的解决方案。阅读本章:static.springsource.org/spring/docs/3.0.x/…(很难阅读,但值得努力),另请阅读 AspectJ in Action (2nd ed):manning.com/laddad2 它提供了对使用或不使用 Spring 的 AOP 的深入介绍【参考方案4】:

这类似于没有匿名类的 Vladimir 解决方案,可能会从此类方法返回值。

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
        
    

【讨论】:

以上是关于Java 从 DAO 中移除重复的 try、catch、finally 样板的主要内容,如果未能解决你的问题,请参考以下文章

怎样在.net项目中移除一个重复的引用?

1.2从链表中移除重复项

链表有序链表中移除重复项

在遍历事件处理程序集合时,如何安全地从回调中移除处理程序?

如何从JavaScript对象中移除一个属性

如何从 UITextField 中移除焦点?