我正在使用Java在Web项目中创建数据库连接。然而,有一件事让我感到困惑;
Filter
或ServletContextListener
?contextDestroyed
方法来关闭连接,但我认为只有在Tomcat服务器停止时它才会起作用。Filter
?以下是我工作的步骤
DataSource
代码Context.xml
文件中创建<resource>
web.xml
代码<resource-ref>
中的资源
contextInitialized
ServletContextListener
中创建连接
doPost
或doGet
方法中执行数据库操作 contextInitialized
方法:
@Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("START CONNECTION");
try {
Context contextEnvironment = (Context) new InitialContext().lookup("java:comp/env/");
DataSource ds = (DataSource) contextEnvironment.lookup("jdbc/lunaruniversity");
try {
Connection con = ds.getConnection();
ServletContext context = event.getServletContext();
context.setAttribute("dbConnection", con);
} catch (SQLException e) {
e.printStackTrace();
}
} catch (NamingException e) {
e.printStackTrace();
}
}
servlet&#39; doGet
方法:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Connection con = (Connection) getServletContext().getAttribute("dbConnection");
String saveStudent = request.getParameter("saveStudent");
String insertSQL = "INSERT INTO STUDENT (FNAME, LNAME, EMAIL, PHONE, STATE, ZIPCODE) VALUES(?,?,?,?,?,?)";
String fName = request.getParameter("fName");
String lName = request.getParameter("lName");
String email = request.getParameter("email");
String phone = request.getParameter("phone");
String state = request.getParameter("state");
String zipCode = request.getParameter("zipCode");
try {
java.sql.PreparedStatement ps = con.prepareStatement(insertSQL);
ps.setString(1, fName);
ps.setString(2, lName);
ps.setString(3, email);
ps.setString(4, phone);
ps.setString(5, state);
ps.setString(6, zipCode);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
contextDestroyed
方法:
@Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("CLOSE CONNECTION");
DataSource ds = (DataSource) event.getServletContext().getAttribute("dbConnection");
try {
if (!ds.getConnection().isClosed()) {
System.out.println("CONNECTION IS CLOSED");
ds.getConnection().close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
答案 0 :(得分:3)
1,2和3:以上都不是。
当您需要启动事务时,您将从DataSource获得连接。您在参与该事务的所有方法调用中传递该连接。然后提交并关闭连接。使用try-with-resources确保它始终关闭,即使出现异常:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
try (Connection connnection = dataSource.getConnection()) {
// use the connection
connection.commit();
}
}
答案 1 :(得分:2)
使用池时,不应该创建 Connection
。该池负责实际创建连接。
你永远不应该在全局记忆中放置一个开放的Connection
,例如ServletContext
。连接不应该由多个线程同时使用。请参阅“Is java.sql.Connection thread safe?”。
因此,对于您要执行的操作,请使用Filter
,并将Connection
存储为请求属性。
更好的是,在servlet方法中使用try-with-resources块,如answer by JB Nizet所示,因此除非servlet实际需要,否则不要从池中获取连接。
答案 2 :(得分:2)
在Web应用程序中,来自用户的每个http请求都在其自己的线程中(或通过线程池)运行。拥有所有请求共享的全局连接对象并不是一个好主意,因为一次只有一个线程可以使用它,它将成为您的应用程序的瓶颈。
建议的设置是使用在服务器启动时初始化的连接池(例如C3P0)(通过config自动或在ServletContextListener中手动)。连接池将根据需要创建和关闭连接。当您收到http请求(servlet的doPost或doGet)时,您只需从池中获取连接,并在处理完该请求后将其返回池中。
您可以使用ServletFilter自动执行该部分。在过滤器中,在调用chain.doFilter()
之前,您将从池中获得连接并将其存储在请求属性中。在致电doFilter()
之后,您将其返回到游泳池。