MySQL 连接池与 JERSEY

标签 mysql jdbc jersey connection-pooling

我正在使用 Jersey 和 MySQL 开发 RESTful API。

我实际上使用 JDBC 驱动程序连接到数据库,并且每次想要访问它时都会创建一个新连接。由于这显然是内存泄漏,因此我开始实现 ServletContextClass 类,但我不知道当我需要获取 SQL 查询结果时如何调用该方法。

这是我做错的方法:

DbConnection.java 公共(public)类 DbConnection {

    public Connection getConnection() throws Exception {
        try {
            String connectionURL = "jdbc:mysql://root:port/path";
            Connection connection = null;
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            connection = DriverManager.getConnection(connectionURL, "root", "password");
            return connection;
        }

        catch (SQLException e) {
            throw e;
        }
    }
}

DbData.java

public ArrayList<Product> getAllProducts(Connection connection) throws Exception {
    ArrayList<Product> productList = new ArrayList<Product>();
    try {
        PreparedStatement ps = connection.prepareStatement("SELECT id, name FROM product");
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Product product = new Product();
            product.setId(rs.getInt("id"));
            product.setName(rs.getString("name"));
            productList.add(product);
        }
        return productList;
    } catch (Exception e) {
            throw e;
    }
}

资源.java

@GET
@Path("task/{taskId}")
@Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(@PathParam("taskId") int taskId) throws Exception {
    try {
        DbConnection database= new DbConnection();
        Connection connection = database.getConnection();
        Task task = new Task();
        DbData dbData = new DbData();
        task = dbData.getTask(connection, taskId);

        return Response.status(200).entity(task).build();
    } catch (Exception e) {
        throw e;
    }
}

这是我最终尝试实现新类的地方:

ServletContextClass.java

public class ServletContextClass implements ServletContextListener {

    public Connection getConnection() throws Exception {
        try {
            String connectionURL = "jdbc:mysql://root:port/path";
            Connection connection = null;
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            connection = DriverManager.getConnection(connectionURL, "root", "password");
            return connection;
        } catch (SQLException e) {
            throw e;
        }
    }

    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("ServletContextListener started");
        DbConnection database = new DbConnection();
        try {
            Connection connection = database.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void contextDestroyed(ServletContextEvent arg0) {
        System.out.println("ServletContextListener destroyed");
        //con.close ();       
    }

}

但问题是,我不知道下一步该做什么。有什么帮助吗?谢谢

最佳答案

您需要将 Connection 变量设置为 ServletContext 的一个属性。另外,我建议使用 connection 作为静态类变量,以便您可以在 contextDestroyed 方法中关闭它。 您稍后可以在任何 servlet 中检索connection 属性来执行数据库操作。

public class ServletContextClass implements ServletContextListener {

    public static Connection connection;

    public Connection getConnection(){
        try {
            String connectionURL = "jdbc:mysql://root:port/path";
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            connection = DriverManager.getConnection(connectionURL, "root", "password");
        } catch (SQLException e) {
            // Do something
        }
    }

    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("ServletContextListener started");
        getConnection();
        arg0.getServletContext().setAttribute("connection", connection);
    }

    public void contextDestroyed(ServletContextEvent arg0) {
        System.out.println("ServletContextListener destroyed");
        try{
            if(connection != null){
                connection.close();
            }
        }catch(SQLException se){
            // Do something
        } 
    }

}

最后访问 Servlet(资源)内的 connection 属性。确保将 @Context ServletContext 传递给您的 Response 方法,以便您可以访问上下文属性。

@GET
@Path("task/{taskId}")
@Consumes(MediaType.APPLICATION_JSON)
public Response getInfos(@PathParam("taskId") int taskId, @Context ServletContext context) throws Exception {
    try {
        Connection connection = (Connection) context.getAttribute("connection");
        Task task = new Task();
        DbData dbData = new DbData();
        task = dbData.getTask(connection, taskId);

        return Response.status(200).entity(task).build();
    } catch (Exception e) {
        throw e;
    }
}

现在我们已经解决了您当前的问题,我们需要知道这种方法可能会出现什么问题。

首先,您只创建一个将在任何地方使用的connection对象。想象一下,多个用户同时访问您的 API,单个连接将在所有用户之间共享,这会减慢您的响应时间。

其次,您与数据库的连接将在闲置一段时间后终止(除非您将MySql服务器配置为不终止空闲连接,这不是一个好主意),当您尝试访问它时,您将抛出SQLException。这可以在您的 servlet 内部解决,您可以检查您的连接是否已断开,重新创建它,然后更新上下文属性。

使用 Mysql 连接池的最佳方法是使用 JNDI 资源。您可以创建一个连接池,它将由您的servlet 容器管理。您可以将池配置为在连接闲置后断开连接时重新创建连接。如果您使用 Tomcat 作为 Servlet 容器,您可以检查 this开始了解 JNDI 连接池的简短教程。

关于MySQL 连接池与 JERSEY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37441357/

相关文章:

php - 将列与数据数组进行比较

mysql - Access MySQL ODBC连接打开缓慢

php - 如何向本教程添加一些 php,包括 mysql 查询?

mysql - 如何从此 SELECT 中排除重复项?

java - 通过单个连接进行 JDBC 选择查询的效率是否低于包含这些查询的过程?

java - JDBC Clob 和 NClob

java - Jackson - 忽略具有特定名称的属性

java - Hive2 & JDBC - 必填字段 'serverProtocolVersion' 未设置

java - 使我的所有 ajax 响应不可缓存的简单方法

java - 使用 Jersey 将 pojo 解析为 JSON