做系统经常会碰到一些运营人员在后台频繁查询海量数据的操作,导致生产环境奔溃的情况。除了对数据库做优化,已及对查询时间跨度做限制外, 还有一个可行的方法,就是对 action操作数做限制。
既然都是程序员,还是贴代码直观, 直接上代码。
拦截器类 QueryLimitInterceptor 其中sesison中的operNo是用户名。
public class QueryLimitInterceptor extends MethodFilterInterceptor {
private static final long serialVersionUID = 1L;
private static final int LIMIT_COUNT = 1;
private static final String RETURN_MSG = "您的前一个查询未完成,请不要频繁查询";
private static final int SLOW_TIME = 30;
@Override
protected String doIntercept(ActionInvocation arg0) throws Exception {
HttpSession session = ServletActionContext.getRequest().getSession();
String operNo = (String) session.getAttribute("operNo");
String url = ServletActionContext.getRequest().getRequestURI();
AtomicInteger count = null;
long time1 = System.currentTimeMillis();
if (!"".equals(operNo)) {
if (session.getAttribute("queryLimit") != null
&& session.getAttribute("queryLimit") instanceof AtomicInteger) {
count = (AtomicInteger) session.getAttribute("queryLimit");
if (count.get() >= LIMIT_COUNT) {
// 限制当前查询不能超过最大查询;
System.out.println(operNo + " " + url + " 当前查询数 " + count.get()
+ " 限制查询");
return returnError(ServletActionContext.getRequest());
} else {
// 计数增加1
count.incrementAndGet();
System.out.println(operNo + " " + url + " 当前查询数 " + count.get());
}
} else {
synchronized (session) {
if (session.getAttribute("queryLimit") == null) {
count = new AtomicInteger(1);
System.out.println(operNo + " " + url + " 当前初始化查询数 " + count.get());
session.setAttribute("queryLimit", count);
}
}
}
}
String result = null;
try {
result = arg0.invoke();
} finally {
// 执行完后减少1
count.decrementAndGet();
System.out.println(operNo + " " + url + " 执行后查询数 " + count.get());
long time2 = System.currentTimeMillis();
if ((time2 - time1)/1000 >= SLOW_TIME ) {
System.out.println(operNo + " " + url + " 慢查询操作,耗时 " + (time2 - time1)/1000 + "秒");
}
}
return result;
}
private String returnError(HttpServletRequest request) {
request.setAttribute("errorMsg", "<script language=javascript>alert('"
+ RETURN_MSG + "');history.back()</script>");
return "errorMsg";
}
}
配置文件 struts2.xml 其中 includeMethods里包含的都是要做查询限制的action方法。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="basePackage" extends="struts-default">
<interceptors>
<interceptor name="queryLimt"
class="com.kanesoft.interceptor.QueryLimitInterceptor" />
<interceptor-stack name="mydefault">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="queryLimt" >
<param name="includeMethods">frzBillList,acctInfoList,getPayBillList,queryINBill,queryDetail,getOrderFile,transDetail</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="mydefault" />
</package>
<struts>
最终实现的效果就是 用户做一次查询,如果查询时间较长,然后用户再一次做查询,系统则会对提示“您的前一个查询未完成,请不要频繁查询”的提示,并终止操作。
另外一功能便是对 操作员,操作URL 和超过30秒的查询操作进行记录,加以警示。