2010-10-20 118 views
2

我正在运行一个Spring MVC应用程序,该应用程序由我使用JDBC访问的MySQL数据库支持。我一直在使用相同的代码,并且从未真正看过我是否正确使用它(正确使用连接池等)。错误地使用JDBC连接池

我知道有JDBCTemplate那里,我已经考虑过使用它,但如果唯一的好处是我只是不必写样板代码,那么我不太相信我应该使用它。事实上,我更喜欢我的代码在JDBCTemplate代码上的可读性。

下面是我的DAO中的代码,出于某种原因,我觉得我没有正确使用ConnectionPooling。

public Agent get(Integer id){ 
    ConnectionPool pool = new ConnectionPool(); 
    Connection connection = pool.getConnection(); 
    PreparedStatement ps = null; 
    try{ 
     String query = "SELECT * FROM agent where id= ?"; 
     ps = connection.prepareStatement(query); 
     ps.setInt(1,id); 
     ResultSet rs = ps.executeQuery(); 

     Agent agent = null; 
     if(rs.next()){ 
      agent = new Agent(); 
      agent.setFirstName(rs.getString(1)); 
      agent.setLastName(rs.getString(2)); 
      agent.setStreet(rs.getString(3)); 
      agent.setCity(rs.getString(4)); 
      agent.setZip(rs.getString(5)); 
      agent.setState(rs.getString(6)); 
      agent.setUsername(rs.getString(7)); 
      agent.setPassword(rs.getString(8)); 
      agent.setId(rs.getInt(9)); 
      agent.setEmail(rs.getString(10)); 
     } 
     return agent; 
    } 
    catch(SQLException e) 
    { 
     e.printStackTrace(); 
     return null; 
    } 
    finally{ 
     ConnectionUtility utility = new ConnectionUtility(); 
     utility.closePreparedStatement(ps); 
     pool.freeConnection(connection); 
    } 
} 

上面的代码是什么,我担心的绝大多数是不正确的,但我有也可以有助于不良做法/不当代码的一些实用程序类。

以下是我的ConnectionUtility类。

public class ConnectionUtility{ 

public static void closeStatement(Statement s){ 
    try{ 
     if(s != null){ 
      s.close(); 
     } 
    } 
    catch(SQLException e){ 
     e.printStackTrace(); 
    } 
} 
public void closePreparedStatement(Statement ps){ 
    try{ 
     if(ps != null){ 
      ps.close(); 
     } 
    } 
    catch(SQLException e){ 
     e.printStackTrace(); 
    } 
} 
public static void closeResultSet(ResultSet rs){ 
    try{ 
     if(rs != null){ 
      rs.close(); 
     } 
    } 
    catch(SQLException e){ 

    } 
} 

} 

这是我连接池类,

public class ConnectionPool { 
private static ConnectionPool pool = null; 

public ConnectionPool(){ 
} 
public static ConnectionPool getInstance(){ 
    if(pool == null){ 
     pool = new ConnectionPool(); 
    } 
    return pool; 
} 

@SuppressWarnings("static-access") 
public Connection getConnection(){ 
    try{ 

     return ConnectionFactory.getInstance().getConnection(); 
    } 
    catch(SQLException e){ 
     e.printStackTrace(); 
     return null; 
    } 

} 
public void freeConnection(Connection c){ 
    try{ 
     c.close(); 
    } 
    catch(SQLException e){ 
     e.printStackTrace(); 
    } 
} 
} 

再次,我觉得我真的很喜欢使用所有这些类的错误,即使一切正常,但没有已经投入生产中的测试。

我更喜欢呆在JDBC中,所以请不要将切换到另一个。

+1

Jeez,安顿下来。问题是关于如何改进他的代码。您的评论没有帮助。 – 2010-10-20 00:35:42

+0

我正在改进他的代码。使用Spring将是一个巨大的进步。这比你知道的更有帮助。 – duffymo 2010-10-20 00:53:55

+3

建议Spring有帮助。告诉他他的代码是可怕的,你永远不会和他一起工作,并且他不应该获得他的学位不是。 – 2010-10-20 00:58:10

回答

6

其中核心春天的原理是dependency injection。 Spring基于一种观点,即将类使用的组件注入到该类中会导致更容易阅读,更容易测试,更易于维护的代码(例如您的类/代码)(例如您的get()方法)负责找到他们自己的依赖关系。

举个更具体的例子:你的get()方法依赖于至少两个其他类:1)“连接池”和2)连接本身。 get()方法有深入的知识,它需要如何获得这些实例

作为替代你的编码这里的风格,与DI接近拥有您get()方法将有注入它Connection(或Datasource)(通过setter方法或构造函数注入)的类。

现在,为什么这个简单的改变让代码变得更容易和更好?

因为get()方法不再需要关心的细节不是它的核心责任。 get()方法的核心责任是知道如何获得Agent给定的Integer id。为什么这种方法还需要知道1)从哪里获得连接以及2)您想要连接连接?

当你想改变这种连接逻辑时会发生什么?您需要触摸的代码,每个数据访问方法在您的应用程序中。这将是一个远远超出它所需要的更难的改变。

这是依赖注入的力量:它允许您更改细节(例如JDBC连接来自何处),而不必更改恰好使用这些细节的代码。

至于你的实际连接池的代码,就好像你是误会两个概念:

1)您ConnectionPool号称要成为一个单身,但你暴露一个公共的构造,让合作者完全违约的目的具有ConnectionPool的单个实例。

2)您的连接池实际上并不是一个连接池!连接池的想法是打开N个到数据库的连接,然后将这N个连接中的每一个连接分配给需要按需连接的代码。这里的核心思想是,您可以回收连接并避免为每个请求打开新连接的昂贵成本。在连接池中,当使用连接的代码通过连接完成时,物理连接并未实际终止 - 相反,连接句柄仅返回到池中,以供其他请求/线程/方法再次使用。

最重要的是,在使用连接池的应用程序负责数据访问代码通常甚至不知道它的连接被汇集 - 相反,DAO只是有一个DataSource接口的引用和DAO有当它要求DataSource进行连接或发布连接时会发生什么,不知道实际发生了什么。因此,您可以从负责高级逻辑的代码中抽象出“我该如何连接”的细节,例如“如何从此整数获取代理?”。这种抽象可以让你改变你的应用程序的一层,而不用重写所有其他层 - 你已经分离了各层,每个层只关心它实际负责的内容。

我强烈建议你不仅要阅读关于连接池的想法,还要阅读Dependency Injection。为什么你会在没有DI组件的情况下使用Spring?至于连接池,为什么花时间通过编写自己的代码重新发明轮子,而不是使用一些已有的和流行的库,如commons-dbcpc3p0?不要重新发明轮子,而要使用现有的库(这种库比您的家酿解决方案更可能存在缺陷),并专注于构建您的实际应用程序。

3

有两个问题与您的代码:

1)在创建每次调用get()一个新的连接池对象。你的ConnectionPool类被设计为一个单例,所以通过使构造函数保持私有并将你的客户代码改为ConnectionPool pool = ConnectionPool.getInstance()来强制执行它。

2)与ConnectionUtility基本相同的问题。你有静态方法,但你以非静态方式使用它们。更换

ConnectionUtility utility = new ConnectionUtility(); 
utility.closePreparedStatement(ps); 

ConnectionUtility.closePreparedStatement(ps); 

,使ConnectionUtility构造私人和类决赛。

单身人士和实用工具类可能会很棘手,所以我建议您使用Findbugs等静态分析工具来解决这些问题。它会警告你,当你有一个看起来应该是单身人士或实用程序类的类,但没有以这种方式使用它。