JDBC连接池的使用不正确

The*_*boy 2 java mysql jdbc

我正在运行一个Spring MVC应用程序,由我使用JDBC访问的MySQL数据库提供支持.我一直在使用相同的代码,并且从未真正了解我是否正确使用它(正确使用连接池等).

我知道那里有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);
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码是我担心的最不正确的,但我有一些实用程序类,也可能导致不良做法/不正确的代码.

下面是我的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){

    }
}

}
Run Code Online (Sandbox Code Playgroud)

这是我的ConnectionPool类,

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();
    }
}
}
Run Code Online (Sandbox Code Playgroud)

再一次,我觉得我确实错误地使用了所有这些类,即使一切都工作正常,但在生产中没有进行任何测试.

我更喜欢使用JDBC,所以请不要建议切换到另一个.

mat*_*t b 6

Spring 的核心原则之一是依赖注入.Spring基于这样一种信念,即将类所使用的组件注入该类会导致更容易阅读,更易于测试和更易于维护的代码,而不需要使用类/代码(例如您的get()方法)找到自己的依赖项.

作为一个更具体的术语的例子:你的get()方法至少取决于其他两个类:1)"连接池"和2)连接本身.该get()方法非常了解如何获取这些实例.

作为此处编码风格的替代方法,使用DI方法,拥有您的get()方法的类将Connection(或Datasource)注入其中(通过setter或构造函数注入).

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

因为该get()方法不再需要关注不是其核心责任的细节.该get()方法的核心职责是知道如何获得Agent给定的Integer id.为什么这个方法还需要知道1)从哪里获取连接和2)你想要池连接?

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

这是依赖注入的强大功能:它允许您更改细节(例如JDBC连接的来源),而不必更改使用这些细节的代码.

至于你的实际连接池代码,似乎你误解了两个概念:

1)您ConnectionPool声称想要成为Singleton,但是您公开了一个公共构造函数,允许协作者完全默认具有单个实例的目的ConnectionPool.

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

最重要的是,在使用连接池的应用程序中,负责数据访问的代码通常甚至不知道它的连接正在被合并 - 相反,DAO只是引用了一个DataSource接口,DAO不知道它实际发生了什么.请求DataSource连接或释放连接时发生的情况.因此,您可以从负责高阶逻辑的代码中抽象出"我如何连接"的细节,例如"如何从此整数中获取代理?".这种抽象允许您在不重写所有其他层的情况下更改应用程序的一个层 - 您已经拆分了层,每个层只关注它实际负责的内容.

我强烈建议你不仅要了解连接池的概念,还要阅读依赖注入.为什么在没有DI组件的情况下你会使用Spring?至于连接池,为什么要花时间通过编写自己的方法来重新发明轮子,而不是使用一些已经存在且流行的库,如commons-dbcpc3p0?而不是重新发明轮子,使用现有的库(不太可能有比家庭酿造的解决方案更多的错误),并专注于构建您的实际应用程序.