无论进入哪个网站,用户注册是必不可少的一部分,用户注册所需要的时间是影响用户体验最重要的一环,今天我们我们的任务就是以用户注册为例,使用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 stub
sql_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