web应用并发请求;数据库连接异常
在做一个简单的广告统计功能,就是在页面加载完成的时候发送一个ajax请求,这个参数有来源站点域名:document.referer;当前访问地址:window.localtion.herf;目标地址:xxx。
请求到了action,action把接受到的参数传递给一个service。在这个service的方法里,把接受到的参数保存起来,并启动一个新的线程,把保存的参数给这个线程。然后这个方法就执行结束了,action也就返回了,接下来的统计操作就由新启动的线程处理。统计数据放在map里,程序会在一个时间段向数据库写入记录,在run方法里会有读数据库的操作,当并发量大的时候会抛数据库连接异常。代码如下:请指教我这样做合理不,或者出现这种异常的解决办法?
package cn.boccfc.css.adcounter.service.impl;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import cn.boccfc.css.adcounter.action.front.CountElement;
import cn.boccfc.css.adcounter.entity.Advertise;
import cn.boccfc.css.adcounter.entity.VisitCounter;
import cn.boccfc.css.adcounter.manager.AdvertiseMng;
import cn.boccfc.css.adcounter.manager.VisitCounterMng;
import cn.boccfc.css.adcounter.service.AdcounterService;
public class AdcounterServiceImpl implements AdcounterService {
private Map<Long,CountElement> marketMap=Collections.synchronizedMap(new HashMap<Long,CountElement>());
@Autowired
private VisitCounterMng visitCounterMng;
@Autowired
private AdvertiseMng advertiseMng;
public void count(String fromUrl,String targetUrl,String currentUrl){
Map<String ,String> map=new HashMap<String,String>();
map.put("fromUrl",fromUrl);
map.put("targetUrl",targetUrl);
map.put("currentUrl",currentUrl);
CounterThread counter=new CounterThread(map);
counter.start();
}
/**
* 保存至数据库
* @param advertise
* @param ce
* @param map
*/
private void insertDB(Advertise advertise,CountElement ce, Map<String, String> map){
//根据广告id和当前日期查询广告统计表
VisitCounter counter = visitCounterMng.findByAdAndDate(advertise.getId(), new Date());
//如果查询到当天该广告的统计记录,则作更新,否则做新增
if(counter != null){
counter.setVisitTimes(counter.getVisitTimes() + ce.getSum());
}else{
counter = new VisitCounter();
counter.setVisitTimes(ce.getSum());
}
counter.setVisitDate(ce.getLastUpdateDay());
counter.setCurrenttUrl(map.get("currentUrl"));
counter.setTargetUrl(map.get("targetUrl"));
counter.setAdvertise(advertise);
visitCounterMng.saveOrUpdate(counter);
}
/**
* 根据配置广告添加新键
* @param advertise
*/
private void createNewElement(Advertise advertise) {
CountElement element =new CountElement(new Date(),System.currentTimeMillis(),1);
marketMap.put(advertise.getId(), element);
}
/**
* 获取配置广告对应的统计元素
* @param advertise
*/
private CountElement getElement(Advertise advertise){
return marketMap.get(advertise.getId());
}
/**
* 更新配置广告对应的统计元素
* @param advertise
*/
private void updateElement(Advertise advertise,CountElement newCountElement){
marketMap.put(advertise.getId(), newCountElement);
}
/**
* 移除配置广告对应的统计元素
* @param advertise
*/
private CountElement removeElement(Advertise advertise){
return marketMap.remove(advertise.getId());
}
class CounterThread extends Thread{
private Map<String ,String> map;
public CounterThread(Map<String, String> map) {
this.map = map;
}
@Override
public void run() {
//1.根据访问的来源url确定广告对象
Advertise advertise = advertiseMng.findByDomain(map.get("fromUrl"));
CountElement ce = null;
if(advertise!=null){
ce = getElement(advertise);
if(ce != null ){
//把昨天或者更新时间超过20分钟的数据保存到数据库,重新累计
if(!DateUtils.isSameDay(ce.getLastUpdateDay(),new Date()) ||
System.currentTimeMillis()-ce.getLastUpdateTimeMilles()>120000){
insertDB(advertise,ce,map);
createNewElement(advertise);
}else{
//否则累计到缓存
ce.setSum(ce.getSum()+1);
updateElement(advertise, ce);
}
}else{
createNewElement(advertise);
}
}
}
}
}