【问题标题】:MySQL connection pooling with JERSEY使用 JERSEY 的 MySQL 连接池
【发布时间】:2016-09-23 07:22:09
【问题描述】:

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

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

这是我做错的地方:

DbConnection.java 公共类 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;
    }
}

Resource.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 ();       
    }

}

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

【问题讨论】:

    标签: mysql jdbc jersey connection-pooling


    【解决方案1】:

    您需要将 Connection 变量设置为 attributeServletContext。另外,我建议使用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,单个 connection 将在所有用户之间共享,这会减慢您的响应时间。

    其次,您对 DB 的connection 将在闲置一段时间后死掉(除非您将MySql 服务器配置为不杀死空闲连接,这不是一个好主意),当您尝试访问它时,您将让SQLExceptions 到处乱扔。这可以在您的 servlet 中解决,您可以检查您的连接是否已失效,重新创建它,然后更新上下文属性。

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

    【讨论】:

    • 谢谢@imranarshad,我只需要在getConnection()函数和一些catch返回,但它可以工作。我会调查你信息的第二部分。这是个好建议
    猜你喜欢
    • 2013-08-20
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 2013-09-01
    相关资源
    最近更新 更多