web应用并发请求;数据库连接异常

pureloveboy 2013-01-07 12:59:38
在做一个简单的广告统计功能,就是在页面加载完成的时候发送一个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);
}
}
}

}
}
...全文
1124 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
为啥呢 2013-01-08
  • 打赏
  • 举报
回复
引用 4 楼 huangqingxi1 的回复:
引用 3 楼 xodbc 的回复:在异常中指出了你的连接池上限是10个连接,如果增加缓存队列,那应该是每次只有10个请求被同时处理... 为啥要1个连接一个请求呢?建议用预处理对象。用预处理对象是什么意思,你指的什么,谢谢
我指的是java.sql.PreparedStatement类型,不论多少个线程,类似的请求都可以封装为这样的对象,只要不使用程序级别的事务,不过貌似你使用了事务,那就没办法了...如果可用连接数有限那只能同步执行额外的请求了
pureloveboy 2013-01-07
  • 打赏
  • 举报
回复
引用 3 楼 xodbc 的回复:
在异常中指出了你的连接池上限是10个连接,如果增加缓存队列,那应该是每次只有10个请求被同时处理... 为啥要1个连接一个请求呢?建议用预处理对象。
用预处理对象是什么意思,你指的什么,谢谢
为啥呢 2013-01-07
  • 打赏
  • 举报
回复
在异常中指出了你的连接池上限是10个连接,如果增加缓存队列,那应该是每次只有10个请求被同时处理... 为啥要1个连接一个请求呢?建议用预处理对象。
pureloveboy 2013-01-07
  • 打赏
  • 举报
回复
[Thread-59]-[13-01-07 15:42.381][INFO][617]-o.l.p.OraclePool-Proxool statistics legend: "s - r (a/t/o)" > s=served, r=refused (only shown if non-zero), a=active, t=total, o=offline (being tested) [Thread-59]-[13-01-07 15:42.416][INFO][158]-o.l.p.OraclePool-000083 -000001 (10/10/00) - Couldn't get connection because we are at maximum connection count and there are none available [Thread-59]-[13-01-07 15:42.417][ERROR][101]-o.h.u.JDBCExceptionReporter-Couldn't get connection because we are at maximum connection count (10/10) and there are none available [Thread-59]-[13-01-07 15:42.417][ERROR][101]-o.h.u.JDBCExceptionReporter-Couldn't get connection because we are at maximum connection count (10/10) and there are none available [Thread-59]-[13-01-07 15:42.420][ERROR][101]-o.h.u.JDBCExceptionReporter-Couldn't get connection because we are at maximum connection count (10/10) and there are none available [Thread-59]-[13-01-07 15:42.420][ERROR][101]-o.h.u.JDBCExceptionReporter-Couldn't get connection because we are at maximum connection count (10/10) and there are none available Exception in thread "Thread-59" org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.exception.GenericJDBCException: Cannot open connection at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:599) at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:374) at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:263) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) at $Proxy79.findByDomain(Unknown Source) at cn.boccfc.css.adcounter.service.impl.AdcounterServiceImpl$CounterThread.run(AdcounterServiceImpl.java:108) Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140) at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52) at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449) at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167) at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142) at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85) at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1463) at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:558) ... 7 more Caused by: java.sql.SQLException: Couldn't get connection because we are at maximum connection count (10/10) and there are none available at org.logicalcobwebs.proxool.Prototyper.quickRefuse(Prototyper.java:309) at org.logicalcobwebs.proxool.ConnectionPool.getConnection(ConnectionPool.java:152) at org.logicalcobwebs.proxool.ProxoolDataSource.getConnection(ProxoolDataSource.java:97) at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82) at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446) ... 12 more
为啥呢 2013-01-07
  • 打赏
  • 举报
回复
建议贴一下异常。 一般大并发量的请求是要做缓存的,因为你不知道实际应用环境下底层能否处理这样的并发量,所以因该限制从缓存到底层的并发量,无法满足这个并发量的请求都在缓存中排队。 在使用线程时应该池化线程,并给出池的尺寸,原因同上。 虚拟的东西是可以无限的,但用来支撑这些虚拟环境的物理的设备都是有限的,所以一个系统越往底层,可分配资源越有限,底层做的不好就会暴露出LZ这样的问题。

67,514

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧