TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
在制作站点计数器时,如果频繁的访问数数库(比如象哪种每增加一人,便写入数据库的作法),当你的站点有很大的访问量时,必然会影响性能。通常的做法有两种,一是启动一个线程定时写入访问量,二是先在内存中保存访问量,只有当访问量达到一定的数量(比如50人)时才写一次数据库。后者的做法更可取,我开始学习jsp时,不知道写计数器,看到jive中的序列管理器很合适“拿来”作计数器用,少许改动后便用它作了自己的第一个主页计数器(用会话session作为计数)。 后来看了一些开源代码,才了解了高手们是如何写计数器的。
package test;
import java.sql.*;
public class SequenceManager {
/**
*记数增量,内存中访问量满50人时,才将数据写入数据库
*/
private static final int INCREMENT = 50;
/**
*下一个访问量
*/
public static long nextID() {
return nextUniqueID();
}
/**
*当前访问量
*/
public static long currentID() {
return oldid;
}
private static long currentID=0l;
private static long oldid=0l;
private static long maxID=0l;//当内存中的访问量大于此值时,更新数据库。
/**
* 创建一个新的序列管理器
*/
public SequenceManager() {
}
/**
* 返回下一个计数id.
*/
public static synchronized long nextUniqueID() {
if (currentID >= maxID) {
getNextBlock(5);//连5次数据库
}
oldid = currentID;
currentID++;
return oldid;
}
private static void getNextBlock(int count) {
java.sql.Connection Conn=null;
java.sql.Statement Stmt=null;
java.sql.ResultSet Rst=null;
if (count == 0) {
System.err.println("在最后一次尝试获取一个ID时失败, 异常中断...");
return;
}
boolean success = false;
try {
String con_string="jdbc:odbc:cwb";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Conn = DriverManager.getConnection(con_string);
Stmt=Conn.createStatement();
String sqll="select * from count_num";
ResultSet rs=Stmt.executeQuery(sqll);
if (!rs.next()) {
throw new SQLException("Loading the current ID failed. The " +
"jiveID table may not be correctly populated.");
}
long currentID1 = rs.getLong(1);//取数据库中的访问量
long newID = currentID1 + INCREMENT;//访问量加50
sqll="update count_num set num="+newID;
if(currentID>=currentID1) success=Stmt.executeUpdate(sqll)==1;
currentID = currentID1;
maxID = newID;
}
catch( Exception sqle ) {
sqle.printStackTrace();
}
finally {
try { Stmt.close(); }
catch (Exception e) { e.printStackTrace(); }
try { Conn.close(); }
catch (Exception e) { e.printStackTrace(); }
}
if (!success) {
System.err.println("WARNING: failed to obtain next ID block due to " +
"thread contention. Trying again...");
// Call this method again, but sleep briefly to try to avoid thread
// contention.
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException ie) { }
getNextBlock(count-1);//递归调用本方法
}
}
}
测试方法与代码:(在Tomcat 5下调试通过)
先在Access中创建一数据库cwb,并创建表count_num,表中只有一个数字型字段num,并插入一条num为1的记录,jsp测试代码如下:
test.jsp
<%@ page contentType="text/HTML; charset=gb2312" %>
<%@ page import="test.*"%>
<%
String login=(String)session.getAttribute("login");
if(login==null){
%>
总访问量:<%=SequenceManager.nextID() %>
<%
session.setAttribute("login","true");
}else{
%>
总访问量:<%=SequenceManager.currentID() %>
<% } %>
源码下载:http://file.javaxxz.com/2014/9/30/214738172.zip |
|