无论进入哪个网站,用户注册是必不可少的一部分,用户注册所需要的时间是影响用户体验最重要的一环,今天我们我们的任务就是以用户注册为例,使用servlet监听器对用户注册速度进一步优化
用户注册,也就是将用户数据写入到数据库,我们优化注册速度,也就是对后端操作数据库进行优化,像我这种小白用java写注册程序时,每当有用户注册时,就会先连接数据库,然后执行操作语句,最后关闭,多个用户注册时,就是上面流程的循环,我们知道,连接数据库也是需要时间的,所以,这样就有大把的时间都浪费在了连接数据库上,所以我们可以结合监听器来解决这个问题(都是很基础的东西)
先贴两张优化之前和优化之后的用户注册速度对比图
优化之前:
优化之后:
用户注册优化思路:既然时间大多都花在连接数据库上,那我们可以让用户在注册时省去连接数据库这个步骤,并不是不用连接数据库,而是不在用户注册时连接,我们可以提前创建好连接对象,然后用户注册时可以直接调用这个连接对象,那我们什么时候创建连接对象呢?我们可以在服务器启动时就创建好连接对象,那怎样实现在服务器启动时就创建连接对象呢?这就可以借助我们的监听器了,服务器启动时就会创建servlet上下文对象,而监听器可以监听servlet上下文对象的状态,包括何时被初始化,何时被摧毁,以及上下文对象里面存放的数据的变化,这样我们就可以利用监听器的这些功能来完成我们的设想
项目结构
其中Listener.java是监听器接口的实现类
代码部分
AddInfoDao.java部分
package dao;import java.sql.*;import java.util.Iterator;import java.util.Map;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;public class AddInfoDao {private static Connection conn = null;private static PreparedStatement pst = null;public static boolean addinfo(String a,String b,String c,String d,HttpServletRequest request) {boolean result = false;// 创建servlet上下文对象 ServletContext application = request.getServletContext();// 获取上下文对象中存放的Map@SuppressWarnings("unchecked") Map<Connection, Boolean> allconn = (Map<Connection, Boolean>) application.getAttribute("allconn"); Iterator<Connection> keys = allconn.keySet().iterator();// 从Map中获取连接对象while (keys.hasNext()) {// 判断连接对象是否正在被使用,如果为true,表示可以使用,如果为false,表示正在被使用if (allconn.get(keys.next()) == true) { conn = keys.next();// 使用一个连接对象时,将此连接对象的使用状态标识为false allconn.put(conn, false);// 因为我们正在使用一个连接对象,所以我们要将此连接对象的状态更新到servlet上下文中,这样其他用户才可以知道此连接对象已被使用 application.setAttribute("allconn", allconn);break;}}try {// 执行添加数据的SQL语句 pst = conn.prepareStatement("insert into demo values (?,?,?,?)"); pst.setString(1, a); pst.setString(2, b); pst.setString(3, c); pst.setString(4, d); pst.executeUpdate(); result = true;} catch (SQLException e) {// TODO Auto-generated catch block e.printStackTrace();}finally {// 当我们执行完sql语句不再使用连接对象时,将连接对象的表示状态改为true,表示其他用户可以使用此连接对象 allconn.put(conn, true);// 改变完连接对象的状态后,要更新到上下文中,这样其他用户才可以知道 application.setAttribute("allconn", allconn);}return result;}}
GetInfoServlet.java部分
package getinfo;import java.io.IOException;import java.util.Date;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import dao.AddInfoDao;@WebServlet("/GetInfoServlet")public class GetInfoServlet extends HttpServlet {private static final long serialVersionUID = 1L; public GetInfoServlet() {super();// TODO Auto-generated constructor stub}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); String a = request.getParameter("a"); String b = request.getParameter("b"); String c = request.getParameter("c"); String d = request.getParameter("d"); Date time1 = new Date();boolean result = AddInfoDao.addinfo(a, b, c, d, request); Date time2 = new Date(); System.out.println("用户注册用时为: " + (time2.getTime()-time1.getTime()) + "毫秒");if (result == true) { System.out.println("添加成功");}else { System.out.println("添加失败");}}}
Listener.java部分
package listener;import java.sql.*;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import javax.servlet.ServletContext;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;import util.SqlServerConnection;// 实现ServletContextListener接口,监听servlet上下文的状态public class Listener implements ServletContextListener {private Connection conn = null;// 创建Map用来存放数据库连接对象 Map中的键用来存放数据库连接对象 值用来标识此连接对象是否被使用 Map<Connection, Boolean> allconn = new HashMap<Connection, Boolean>();// servlet上下文初始化时执行此方法public void contextInitialized(ServletContextEvent sce) {// 创建10个连接对象for (int i = 0; i < 10; i++) { conn = SqlServerConnection.sql_connection(); System.out.println("创建数据库连接对象 " + conn); allconn.put(conn, true);}// 将存放连接对象的Map存放在servlet上下文中,从服务器启动到服务器关闭期间可以随时随地使用 sce.getServletContext().setAttribute("allconn", allconn);}// servlet上下文被摧毁时执行此方法public void contextDestroyed(ServletContextEvent sce) {// 创建Servlet上下文对象,生命周期从服务器启动到服务器关闭 ServletContext application = sce.getServletContext();// 获取存放数据库连接对象的map@SuppressWarnings("unchecked") Map<Connection, Boolean> allconn = (Map<Connection, Boolean>) application.getAttribute("allconn");// 获取所有数据库连接对象 连接对象我们存放在了Map的键中 所以我们要获取Map中所有的键 Iterator<Connection> it = allconn.keySet().iterator();// 循环关闭所有数据库连接对象while (it.hasNext()) { Connection connection = (Connection) it.next();try { connection.close(); System.out.println("关闭数据库连接对象 " + connection);} catch (SQLException e) {// TODO Auto-generated catch block e.printStackTrace();}}}}
SqlServerConnection.java部分
package util;import java.sql.*;public class SqlServerConnection {static Connection conn;static String drive = "com.microsoft.sqlserver.jdbc.SQLServerDriver";static String url = "jdbc:sqlserver://localhost:1433;DatabaseName=ShopSystem";static String username = "sa";static String password = "sa";public static Connection sql_connection() {try {// 注册驱动 Class.forName(drive);} catch (ClassNotFoundException e) {// TODO Auto-generated catch block e.printStackTrace();}try {// 创建连接对象 conn = DriverManager.getConnection(url,username,password);} catch (SQLException e) {// TODO Auto-generated catch block e.printStackTrace(); System.out.println("连接失败");}return conn;}public static void main(String[] args) {// TODO Auto-generated method stubsql_connection();}}
web.xml部分
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0"> <display-name>WebTest</display-name> <welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file> </welcome-file-list> <listener> <listener-class>listener.Listener</listener-class> </listener></web-app>
index.html部分
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><center><form action="GetInfoServlet" method="post"><input type="text" name="a"><br/><input type="text" name="b"><br/><input type="text" name="c"><br/><input type="text" name="d"><br/><input type="submit"></form></center></body></html>
jar包获取地址:https://pan.baidu.com/s/1XvJf2bWmLoQPNU8VCjBfgQ
提取码:q0bl