开发了个新网站,里面会存在一些表里需要统计记录点击数,然后按照点击数出一个热门列表的功能.

 

然后就渐渐发现这个是一个很常见的功能,很多表都有这个需求,一般做法都是在每个表中加Hit字段,然后order by hit 取列表,这也没什么,关键是我这个小站点,后台在本机,没在线上,所以如果更新数据的话,大多数情况就是覆盖更新,然后就会出现一个问题就是这些表里的点击数量又没了,因为被覆盖了.

当然也不是解决不了,就是不要覆盖更新,写个程序慢慢更新,或者写个sql自己定义更新的列.不过我比较懒,还是嫌麻烦,身为程序员,我懒我自豪

所以就有了这个插件形式存在的表,所有的点击数都记录在这个表里,更新的时候不覆盖这个表就好了,耶

表定义

CREATE TABLE `sys_hit` (
`TableName`  varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
`Key1`  varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
`Key2`  varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
`Key3`  varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL  DEFAULT '' ,
`Count`  int(11) NOT NULL DEFAULT 0 ,
PRIMARY KEY (`TableName`, `Key1`, `Key2`, `Key3`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=COMPACT
;

tablename就是要添加hit的表的名称, key1,key2,key3是指该表的主键,

如果但主键就只用Key1,双主键就Key1,Key2,三主键就Key1,Key2,Key3,四主键嘛就再加字段喽

一般三个就够了,一般哦

 

数据实体

    public class HitInfo
    {
        public string TableName { get; set; }
        public int Domain { get; set; }
        public string Key { get; set; }
        public int Count { get; set; }
    }

数据访问类

public class HitDAL
    { 
        /// <summary>
        /// 点击埋点
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="domain"></param>
        /// <param name="key"></param>
        public static void Hit(string tableName, object key1, object key2,object key3)
        {
            try
            {
                var isUpdate = UpdateHit(tableName, key1,key2,key3);
                if (!isUpdate)
                {
                    Insert(tableName, key1, key2, key3);
                }
            }
            catch (Exception ex) //Catch掉,因为不能影响主进程
            {
                LogHelper.Info("点击量更新错误"   ex.Message);
            }
        }

        private static bool UpdateHit(string tableName, object key1, object key2, object key3)
        { 
            using (IDbConnection connection = new MySqlConnection(Config.ConnectionString))
            {
                var result = connection.Execute(@"UPDATE sys_hit SET `Count`=`Count` 1 WHERE TableName=?TableName AND Key1=?Key1 AND `Key2`=?Key2 AND `Key3`=?Key3 ", new { TableName = tableName, Key1 = key1, Key2 = key2, Key3 = key3 });
                return result > 0;
            }
        }

        private static bool Insert(string tableName, object key1, object key2, object key3)
        {
            using (IDbConnection connection = new MySqlConnection(Config.ConnectionString))
            {
                var result = connection.Execute(@"insert sys_hit(TableName,Key1,`Key2`,Key3,`Count`)values(?TableName,?Key1,?Key2,?Key3,?Count)", new { TableName = tableName,  Key1 = key1, Key2 = key2, Key3 = key3, Count = 1 });
                return result > 0;
            }
        }
 
    }

数据访问还是用的Dapper Mysql的形式


现在是调用埋点,双主键

            //更新点击数量
            if (model.Book != null) HitDAL.Hit("tb_book", ((int)this.Domain), id.ToString(), string.Empty);

三主键

            //更新点击数量
            if (model.TVDetail != null) HitDAL.Hit("tb_tvdetail", ((int)this.Domain), tvcode, id);

 

接下来是最关键的取数据了

        /// <summary>
        /// 获取点击榜前10
        /// </summary>
        /// <param name="count"></param>
        /// <param name="domain"></param>
        /// <returns></returns>
      public static List<BookInfo> GetHotBookInfos(int pageSize, EnumDomain domain)
      {
          using (IDbConnection connection = new MySqlConnection(Config.ConnectionString))
          {
              var info = connection.Query<BookInfo>(@"select Id,Title,`Count` from tb_book INNER JOIN sys_hit ON tb_book.id =sys_hit.Key2
                                                     where  domain=?Domain order by `Count` desc limit ?PageSize",
                  new { PageSize = pageSize, Domain = (int)domain }).ToList();
              return info;
          }
      }

在此发现Mysql一个很有意思的性质,条件字段类型不一样也没有问题,好赞!!!

OK,记录到此结束

虽然性能肯定会有所降低,但是就以我的数据量来说,真心没觉得有啥慢的,带来的方便确实是大大的,而且是通用的,噢耶!!!


Leave a Reply