现在的位置: 首页 > 综合 > 正文

简单点播数统计实现方案

2013年01月09日 ⁄ 综合 ⁄ 共 3663字 ⁄ 字号 评论关闭

背景:实现blog网站,每篇文章的点播数统计。

 

简单实现方法:文章每次被打开时update一下数据库。如:

Update blog set visitcount=visitcount+1 where blogid=’文章ID’.

 

当然了,对于一些小型网站,根本没有什么人访问,这种实现方案完全没有问题。但是对于访问量比较大的网站,这种实现方案,很容易造成数据库over掉。

而且在执行update的时候,大多数据库默认都是使用排它锁的,这条数据是被锁住的,别人无法使用。访问量大,被锁住的机率也就大了。

 

我的方案

先把统计数据缓存起来,每N秒钟写一次数据库,这样就大大的减少了数据库的连接次数,以及数据被锁住的机率。

 

缓存实现方案:

定义两个hashtablet1,t2)。一个读一个写(读:从client接收数据。写:数据写入数据库)。每隔N秒写一次数据库。写数据库的时候最好采用异步的方式进行,以防止线程长期占用hashtable().

 

DEMO

统计代码:VisitStatistic.ashx

Blog文章页面中加入标签<script src=” VisitStatistic.ashx”></script>

 

 

VisitStatistic.ashx

代码:

    public class VisitStatistic : IHttpHandler

    {

 

        public void ProcessRequest(HttpContext context)

        {

            context.Response.ContentType = "text/plain";

 

            Statistic();

 

            context.Response.Write("");

        }

 

        private static object threadLock = new object();

        private static Hashtable t1 = Hashtable.Synchronized(new Hashtable());

        private static Hashtable t2 = Hashtable.Synchronized(new Hashtable());

        private static Timer time = new Timer(WriteToDb, null, 10, 6000);

        private static string readtb = "t1";

        private static bool isworking = false;

        

        private void Statistic()

        {

            lock (threadLock)

            {

                Hashtable ht = WriteTb;

                if (ht.ContainsKey(BlogId))

                {

                    ht[BlogId] = (int)ht[BlogId] + 1;

                }

                else

                {

                    ht.Add(BlogId, 1);

                }

            }

        }

 

        private static void WriteToDb(object obj)

        {

            if(isworking) return;

 

            isworking = true;

            Hashtable tb = ReadTb;

            IDictionaryEnumerator enumerator = tb.GetEnumerator();

            List<BlogStatistic> items = new List<BlogStatistic >(tb.Count);

            while (enumerator.MoveNext())

            {

                BlogStatistic item = new BlogStatistic () {

                    VisitCount = (int)enumerator.Value,

                    BlogId = (int)enumerator.Key

                };

 

                items.Add(item);

            }

            tb.Clear();

            if (items.Count > 0)

            {

                ThreadPool.QueueUserWorkItem(AsynWriteToDb, items);

            }

         

 

 

            if (readtb == "t1") readtb = "t2";

            else readtb = "t1";

 

            isworking = false;

        }

 

        private static void AsynWriteToDb(object items)

        {

           

            try

            {

               

                BlogBusiness business = new BlogBusiness ();

 

                business.AddBlogStatistic((List<BlogStatistic>)items);

            }

            catch (Exception ex)

            {

                LogMessage msg = new LogMessage(){

                    Message = "统计数写入数据库异常"

                };

                LogHelper.Error(msg, ex);

            }

        }

 

 

 

        private int BlogId

        {

            get

            {

                string util = HttpContext.Current.Request["blogid"];

                if(string.IsNullOrEmpty(util)

                    ||!Regex.IsMatch(util,@"^"d+$"))

                {

                    HttpContext.Current.Response.End();

                }

 

                return int.Parse(util);

            }

        }

 

        private static Hashtable ReadTb

        {

            get

            {

                if (readtb == "t1")

                {

                    return t1;

                }

                else

                {

                    return t2;

                }

            }

        }

 

        private static Hashtable WriteTb

        {

            get

            {

                if (readtb == "t1")

                {

                    return t2;

                }

                else

                {

                    return t1;

                }

            }

        }

 

        public bool IsReusable

        {

            get

            {

                return false;

            }

        }

    }

抱歉!评论已关闭.