`
xly_971223
  • 浏览: 1283829 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用观察者模式解决点击一次文章 update一次数据库的问题

阅读更多

接上文http://xuliangyong.iteye.com/blog/171240

对于第二种方法现用观察着模式来解决

思路是这样:当点击a文章(id=1234)够10次后 ,通知文章管理器更新点击次数

update article set hit_count = hit_count+10 where id = 1234

这样就减少了访问数据库的次数

 

代码如下:

public class HitCached extends Observable{
	private static final int DEFAULT_MAX_HITS = 10;
	private Map<Long, Integer> hits = Collections.synchronizedMap(new HashMap<Long, Integer>());
	
	/**
	 * 最大点击量。超过该值就更新数据库
	 */
	private int maxHits = DEFAULT_MAX_HITS;
	
	public HitCached(){}
	
	public HitCached(int maxHits){
		this.maxHits = maxHits;
	}
	
	public void put(Long key, Integer value){
		hits.put(key, value);
	}
	
	/**
	 * 为指定key 增加指定的点击量
	 * @param hitIncreased 增加的点数 
	 */
	public void addHit(Long key, Integer hitIncreased){
		if( !hits.containsKey(key) )
				hits.put(key, 0);
		Integer value = hits.get(key);
		if(value + hitIncreased >= maxHits){
			setChanged();
			notifyObservers(KeyValuePair.create(key, value + hitIncreased));
			hits.remove(key);
		}else{
			hits.put(key, value + hitIncreased);
		}
		
	}
	
	public Integer get(Long key){
		return hits.get(key);
	}
	
	public void clear(){
		hits.clear();
	}
	
}
 
public class ArticleManagerImpl extends HibernateGenericDao<Article, Long> implements ArticleManager ,Oberver{
	
	public void update(Observable o, Object arg){
		KeyValuePair keyValue = (KeyValuePair)arg;
		Article article = this.get(keyValue.getKey());
		article.setHitCount(article.getHitCount() + keyValue.getValue());
		save(article);
	}
 

 

action中调用

private static HitCached hitCached = new HitCached(5);

public String view() {
		if (id != null){
			entity = articleManager.get(id);
			hitCached.addObserver(articleManager);
			hitCached.addHit(id, 1);
		}
}

 这样没十次查看才update一次数据库 更新一次缓存 性能得到了大的提升

存在的问题:

停止服务会丢失一些数据 可加一个监听器 来处理

分享到:
评论
20 楼 baibai326 2008-03-26  
这个有意思。
感觉自己造一个Map,存入含有id、最后一次更新时间、计数的bean,
按照更新时间,更新次数,同步数据库。
一个定时的flush或size>? 一定量时主动同步数据库是必须的。
19 楼 neptune 2008-03-25  
galaxystar 写道
其实,这里面,数量更新的可靠性是最重要的一点。
如果中央式缓存可以在大访问量下,很稳定的接受数量count,那么每天凌晨做一次数据库的同步不是更好?


同意其观点,用memcached做中央缓存,memcached有专门的方法来加1和减1,每隔一段时间把数据取出再更新数据库,并清零memcached相关项。
18 楼 FaJa 2008-03-21  
<div class='quote_title'>xly_971223 写道</div><div class='quote_div'><div class='quote_title'>抛出异常的爱 写道</div><div class='quote_div'><div class='quote_title'>myreligion 写道</div><div class='quote_div'>cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?</div><br/>加上定时flush?</div><br/>这确实是个问题 定时flush的话 貌似可行 但一次flush全部数据的话 短时间内可能把数据库压垮 <br/>分批处理的话需要有类似队列结构的Map,按照顺序flush <br/></div><br/><p>设置一个缓存的最大数,每当等于最大数量时,就进行批量更新,并清空缓存</p>
17 楼 galaxystar 2008-03-21  
其实,这里面,数量更新的可靠性是最重要的一点。
如果中央式缓存可以在大访问量下,很稳定的接受数量count,那么每天凌晨做一次数据库的同步不是更好?
16 楼 chbest 2008-03-21  
sorphi 写道
把下面这段代码放到/articles/1234的页面中不是更好么?

<script type="text/javascript" src="/counter/articles/1234"></script>

一般都是这么做的 比较精辟
15 楼 icewubin 2008-03-18  
这种需求不需要同步cache的,就每个cache各管各写库。
超时功能没有的话,自己写一个好了,cache就是一个map,只做10次的这种个数cache,用专业的cache感觉还有点浪费呢。
14 楼 kabbesy 2008-03-18  
点击量是个典型的高频率读写系统,对缓存使用的常规策略一概无效,加上这个数据的价值不是很高(可靠性和事务性要求没有了),所以可以采用这样的方式:

延迟写;
每次写的时候直接从数据库同步到最新数据,使用增量方式;
拒绝分布式缓存(高失效性),拒绝单点缓存(访问频率太高,连接过多),只能够使用单机自己的缓存;
13 楼 myreligion 2008-03-17  
回楼上几位提议,这个问题偶们经历过,实践证明分布式cache是不靠谱的。

如果访问量上来了,用jboss cache这种传说中通讯量很小的cache,在千兆网络中也会造成网络堵塞,影响巨大,性能也差。

对于定时flush,间隔多大?如果间隔很短,其实就没有意义了,而且还可能增大系统负担。如果间隔很大,数据延迟以及内存占用都是问题。

对于这种场景,我觉得有这几个方式值得一试,不过我也没有验证过,呵呵。

1. 普通cache + 超时通知。 cache就是普通的cache,好比ehcache,设定记录最大存活时间(保证延迟可以接受)和最大允许的记录数(限制内存使用),当记录到达最大存活时间或者被挤出缓存时,截获此事件,将移出的记录数据同步到数据库中。这种方式应用比较简单,不过很多cache不支持事件功能比较麻烦。


2. 只cache热门帖子。可以按照业务性质或者点击规则,例如增加一个字段,用于计算帖子最近2分钟的点击次数,如果点击次数操作N次,就认定为热门帖子,对计数进行cache,其他的直接放过。计数增加时,先查看是否在cache中,如果在就更新cache数据,不在就更新数据库,并计算是否需要载入cache。cache中的数据可以定时flush,定时删除,也可以配合方式1进行。

3. 创建一个临时表,把更新信息写入到临时表中,在弄个后台线程慢慢算,慢慢更新。或者弄个单独的统计数据库存着,或是写文件日志。都一个道理。


4. 如果访问量不是非常庞大,好比网站日均pv过千万,直接数据update xxx a = a+ 1 ; 算了,性能还是可以接受的。至少mysql这方面就挺快的。也省事。
12 楼 xly_971223 2008-03-17  
抛出异常的爱 写道
myreligion 写道
cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?

加上定时flush?

这确实是个问题  定时flush的话 貌似可行  但一次flush全部数据的话 短时间内可能把数据库压垮
分批处理的话需要有类似队列结构的Map,按照顺序flush
11 楼 raojl 2008-03-16  
利用JSON微量数据通信
10 楼 EXvision 2008-03-16  
我倒是认为用AOP的方式来解决比较好。

在Struts2下面的话用拦截器的方式解决。

只有当点击量达到一定值,才用拦截器更新数据库。貌似这样能彻底解耦。
不过楼上的兄弟说同步怎么办。似乎是个问题。
9 楼 southben 2008-03-15  
同步怎么办
8 楼 抛出异常的爱 2008-03-14  
myreligion 写道
cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?

加上定时flush?
7 楼 myreligion 2008-03-14  
cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?
6 楼 xly_971223 2008-03-14  
sorphi 写道
我的意思是,记录并更新点击数的行为,放在单独的counter应用中来实现,在业务层解耦。

思路不错
不过貌似跟缓存没直接关系
5 楼 sorphi 2008-03-14  
我的意思是,记录并更新点击数的行为,放在单独的counter应用中来实现,在业务层解耦。
4 楼 xly_971223 2008-03-14  
sorphi 写道
把下面这段代码放到/articles/1234的页面中不是更好么?

<script type="text/javascript" src="/counter/articles/1234"></script>

怎样的思路? 没看明白
3 楼 sorphi 2008-03-14  
Readonly 写道
只在cache中放点击次数,当点击次数被10整除时候,再flush到数据库不是更好么?



cache中存放点击数有两种思路:
1.只存放自上次flush后的新增的点击次数,flush之后置为0。集群环境下这样可以采取local cache。

2.初始化时获取原点击次数,flush之后保留原值。集群环境下只能用central cache。

感觉1更好一些。
2 楼 Readonly 2008-03-14  
只在cache中放点击次数,当点击次数被10整除时候,再flush到数据库不是更好么?
1 楼 sorphi 2008-03-14  
把下面这段代码放到/articles/1234的页面中不是更好么?

<script type="text/javascript" src="/counter/articles/1234"></script>

相关推荐

    浅析Java设计模式【4】——策略.pdf

    尽管给定材料主要讲述的是观察者模式,但在实际开发中,策略模式与观察者模式常常被组合使用,以实现更复杂的功能需求。 #### 2.1 观察者模式概述 观察者模式是一种软件设计模式,它定义了对象之间的依赖关系,当一...

    Observer设计模式

    在Java中,除了标准库提供的Observable和Observer之外,还可以使用第三方库如Guava的EventBus或Spring框架的ApplicationEventPublisher接口来实现观察者模式,这些库提供了更高级的功能和更好的扩展性。 总之,...

    PHP中常用的三种设计模式详解【单例模式、工厂模式、观察者模式】

    - **为何使用**:观察者模式用于解耦对象之间的依赖关系,当一个对象状态改变时,所有依赖于它的对象都能得到通知,而不需要显式地调用这些对象的方法。 - **实现**:定义一个`Subject`接口,它维护一个观察者列表...

    php语言的设计模式

    3. **观察者模式**:定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。在PHP中,它常用于事件驱动编程,如用户登录、购物车操作等。 ```php interface ...

    android_sqlite

    10. **LiveData和Room Persistence Library**:随着Android架构组件的引入,LiveData和Room库提供了更现代的方式来处理SQLite数据库,LiveData提供了一个观察者模式的数据持有者,而Room则提供了更高级别的抽象,...

    [新闻文章]bay_news V1.0.0 北雨新闻信息管理系统_bynews.rar

    【新闻文章】Bay_News V1.0.0 北雨新闻信息管理系统是基于JSP技术开发的一个实用...通过实践这个项目,你不仅能提升你的编程技能,还能增强对Web开发流程的理解,这对于想要从事IT行业的你来说,是一次宝贵的学习机会。

    应用源码之SQLiteSample.zip

    LiveData是Android架构组件之一,提供观察者模式,实时响应数据变化;Room是SQLite的抽象层,简化了数据库操作,同时支持LiveData,使数据管理更加便捷。 9. 数据库升级 随着应用迭代,数据库结构可能需要更新。...

    VS.NET VC .NET写的日志程序.rar

    10. **设计模式**:代码可能体现了常见的设计模式,如单例模式(用于日志类)、工厂模式(用于创建数据库连接)或观察者模式(用于实时更新UI)。 通过深入分析“codesc.net”文件,我们可以学习到上述各个知识点的...

    000000000000000000000000000000000000000000000000000

    8. **软件工程**:设计模式(如单例模式、工厂模式、观察者模式等),版本控制(如Git),以及代码调试和测试方法。 9. **计算机系统**:了解计算机组成原理,包括CPU、内存、I/O设备的工作原理,以及汇编语言的...

    SQLiteStudy

    - Android Architecture Components中的`LiveData`是观察者模式的实现,能自动处理UI与数据的同步。 - `Room`是Google提供的一个SQL方言库,它提供了更高级别的抽象,简化了SQLite操作,同时兼容LiveData,提高了...

    java面试笔试题大汇总 ~很全面 -

    8. **设计模式**:设计模式是解决常见编程问题的模板,如单例、工厂、装饰器、代理、观察者、策略等23种设计模式。熟练运用设计模式可以提高代码的可读性和可维护性。 9. **其他**:还包括异常处理、反射、注解、...

    IBM笔试题—网络资源(整理的)

    - **观察者模式**:事件监听机制的实现原理及案例分析。 #### Oracle相关知识点 ##### 1. SQL基础 - **DDL语句**:CREATE TABLE、DROP TABLE、ALTER TABLE等表定义语句。 - **DML语句**:INSERT、UPDATE、DELETE等...

    Android ContentProvider简单实现

    7. **观察者(Observer)机制**:ContentProvider支持观察者模式,当数据发生变化时,可以通过`ContentResolver.registerContentObserver()`注册一个ContentObserver,它会在数据改变时接收到通知。这对于实时更新UI...

    Note android

    2. 性能优化:为了提升用户体验,可以考虑在异步线程中执行数据库操作,并使用 LiveData 或其他观察者模式来实时更新 UI。 通过以上步骤,我们就实现了一个基本的 Android Notebook 应用。这个应用不仅展示了如何...

    各大公司面试

    - **观察者模式:** 实现事件驱动模型的关键。 - **适配器模式:** 使接口不兼容的类可以一起工作。 ##### 5. 单例模式 **知识点:** - **定义:** 保证一个类只有一个实例,并提供一个全局访问点。 - **实现:** 使用...

    Ruby-chewy高级ElasticsearchRuby框架

    当数据库中的数据发生变化时,Chewy可以通过观察者模式自动更新Elasticsearch中的索引。只需在模型上添加`update_index`方法即可。 ```ruby class User after_save { UsersIndex::User.update_all } end ``` 七、...

Global site tag (gtag.js) - Google Analytics