MySQL 与 JERSEY 的连接池
MySQL connection pooling with JERSEY
我正在开发 RESTful API 和 MySQL。
我实际上是在使用 JDBC 驱动程序连接到数据库,每次我想访问它时我都会创建一个新连接。由于它显然是内存泄漏,我开始实现 ServletContextClass
class 但是当我需要获取 SQL 查询的结果时,我不知道如何调用该方法。
这是我做错的方式:
DbConnection.java
public class 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;
}
}
这是我最终尝试实施新 class:
的地方
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
的 attribute
。另外,我建议使用 connection
作为静态 class 变量,这样您就可以在 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
将在所有用户之间共享,这会减慢您的响应时间。
其次,你的 connection
到数据库会在闲置一段时间后死掉(除非你配置 MySql
服务器不要终止空闲连接,这不是一个好主意),当你尝试要访问它,你会得到 SQLException
s 到处都是。这可以在你的 servlet 内部解决,你可以检查你的连接是否已死,重新创建它,然后更新上下文属性。
处理 Mysql 连接池的最佳方法是使用 JNDI 资源。您可以创建一个 pool of connections
,它将由您的 servlet container
管理。您可以将池配置为在闲置后死机时重新创建连接。如果您使用 Tomcat 作为您的 Servlet 容器,您可以查看 this 简短教程以开始了解 JNDI 连接池。
我正在开发 RESTful API 和 MySQL。
我实际上是在使用 JDBC 驱动程序连接到数据库,每次我想访问它时我都会创建一个新连接。由于它显然是内存泄漏,我开始实现 ServletContextClass
class 但是当我需要获取 SQL 查询的结果时,我不知道如何调用该方法。
这是我做错的方式:
DbConnection.java public class 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;
}
}
这是我最终尝试实施新 class:
的地方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
的 attribute
。另外,我建议使用 connection
作为静态 class 变量,这样您就可以在 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
将在所有用户之间共享,这会减慢您的响应时间。
其次,你的 connection
到数据库会在闲置一段时间后死掉(除非你配置 MySql
服务器不要终止空闲连接,这不是一个好主意),当你尝试要访问它,你会得到 SQLException
s 到处都是。这可以在你的 servlet 内部解决,你可以检查你的连接是否已死,重新创建它,然后更新上下文属性。
处理 Mysql 连接池的最佳方法是使用 JNDI 资源。您可以创建一个 pool of connections
,它将由您的 servlet container
管理。您可以将池配置为在闲置后死机时重新创建连接。如果您使用 Tomcat 作为您的 Servlet 容器,您可以查看 this 简短教程以开始了解 JNDI 连接池。