在我的Web应用程序中对C3P0的这种实现是否正确?这项实施的利弊是什么?

时间:2015-07-27 13:55:13

标签: java servlets connection-pooling c3p0

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

我有一个C3P0的工作实现,但我不知道这是正确的方法,并做到这给出了预期的结果。

以下是我的实施 有一个Datasource文件C3P0实现返回连接。 连接将在servelet init方法上检索,并在destroy方法上关闭。

  • 这种类型的实施会给出预期的结果吗?
  • 我必须在销毁中关闭连接吗?
  • 实现连接池到servlet app的其他方法有哪些?
  • 我喜欢将所有与数据库相关的操作移到单独的类中,在这种情况下,我需要处理的是什么,我必须在servlet中获取连接并在这种情况下传递给db方法吗?
  • 请说明当前实施的利弊

请在

下找到我的连接池实现

返回连接的数据源文件和使用连接的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();
}

}

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

感谢所有人

1 个答案:

答案 0 :(得分:1)

所以,这可以改进。

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

你改变这一点非常重要。除了持久打开Connection的ickiness和资源使用不足之外,在您当前的架构下,对Servlet的同时请求将同时在同一个Connection上运行,这可能导致意外和不正确的行为,特别是如果您的webapp中有servlet,利用交易(因为大多数非常重要的应用程序必须)。

您的DataSource类似乎并不特别有用。为什么不构造c3p0 DataSource而不是使用getConnection()方法定义新类型的对象。我认为你的动机可能只是让静态成员datasource成为真正的DataSource。但是如果你想将DataSource存储为静态成员,你可以在任何地方进行,不需要包装实际的DataSource。

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