我的 Web 应用程序中 C3P0 的这种实现是否正确?这种实施的优缺点是什么?

Do this implimentation of C3P0 in my web application is correct? What are the pros and cons of this implimentation?

我需要在使用 Servlet 和 JSP 页面的 Web 应用程序中实现连接池。我不希望在服务器中的所有应用程序中使用连接池,而是希望在所有 servlet 中实现连接池。

我有一个 C3P0 的工作实现,但我不知道这是否是正确的方法,并且这样做会产生预期的结果。

以下是我的实现 有一个数据源文件 C3P0 实现到 return 连接。 连接将在 servelet init 方法上检索并在 destroy 方法上关闭。

请在下面找到我的连接池实现

return连接的数据源文件和使用连接的 Servelt

数据源文件

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;


public class DataSource {

    // JDBC driver name and database URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://dburl/dbName";

    // Database credentials
    static final String USER = "username";
    static final String PASS = "password";  

    private static DataSource     datasource;
    private ComboPooledDataSource cpds;

    private DataSource() throws IOException, SQLException, PropertyVetoException {
        cpds = new ComboPooledDataSource();
        cpds.setDriverClass("com.mysql.jdbc.Driver"); //loads the jdbc driver

        cpds.setJdbcUrl(DB_URL);
        cpds.setUser(USER);
        cpds.setPassword(PASS);

        // the settings below are optional -- c3p0 can work with defaults
        cpds.setMinPoolSize(5);
        cpds.setAcquireIncrement(5);
        cpds.setMaxPoolSize(20);
        cpds.setMaxStatements(180);

    }

    public static DataSource getInstance() throws IOException, SQLException, PropertyVetoException {
        if (datasource == null) {
            datasource = new DataSource();
            return datasource;
        } else {
            return datasource;
        }
    }

    public Connection getConnection() throws SQLException {
        return this.cpds.getConnection();
    }

}

Servlet

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ConnectionTest
 */
@WebServlet("/ConnectionTest")
public class ConnectionTest extends HttpServlet {


Connection connection = null;
Statement statement = null;

@Override
public void init() throws ServletException {
    super.init();

    try {
        connection = DataSource.getInstance().getConnection();

    } catch (PropertyVetoException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

/**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
 *      response)
 */
protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {

    PrintWriter out = response.getWriter();
    out.println("<h1> Hi</h1>");

    ResultSet resultSet = null;
    try {

        statement = connection.createStatement();
        resultSet = statement
                .executeQuery("SELECT VehicleRegistration  FROM Registration");
        while (resultSet.next()) {

            String first = resultSet.getString("VehicleRegistration");

            // Display values
            out.println("<h1> " + first + "</h1>");

        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        if (resultSet != null)
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        if (statement != null)
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    }
}

@Override
public void destroy() {
    if (connection != null) {
        try {

            connection.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    super.destroy();
}

}

我欢迎所有有助于我改进此代码的建议,即使它太小或太大

提前感谢大家

所以,这是可以改进的。

您的 Servlet 应该获取对 init(...) 中 DataSource 的引用,而不是在 Servlet 的生命周期内保留未完成的 Connection 对象。 Connection 对象应根据需要从连接池数据源获取,而不是长时间保持打开状态。您的 doGet(...) 方法应该获取 Connection(这会很快,因为它已经在池中了!),然后注意在其 finally 块中对 Connection 调用 close()

更改此设置非常重要。除了让 Connection 永远保持打开状态的恶心和资源使用不佳之外,在您当前的体系结构下,对 Servlet 的同时请求将在同一个 Connection 上同时运行,这可能导致意外和不正确的行为,特别是如果您的 webapp 中有 servlets利用事务(大多数重要的应用程序必须如此)。

您的数据源class 似乎不是特别有用。为什么不直接构造 c3p0 DataSource 而不是使用 getConnection() 方法定义一种新的对象。我认为您的动机可能只是让静态成员 datasource 成为一个真正的数据源。但是如果你想将数据源存储为静态成员,你可以在任何地方这样做,没有必要包装实际的数据源。

不过,在 JavaEE Web 应用程序中保存连接池支持的数据源的最佳位置不是作为静态成员。更好的方法是在 ServletContextListenercontextInitialized(...) 中构建数据源,并将数据源存储在应用程序范围内。在 contextDestroyed(...) 中调用 close() c3p0 ComboPooledDataSource,并将其从应用程序范围中删除。