问题
- 从一个例子说起,我们的客户端从服务器获取数据,这里假定获取文章。第一次使用,我们获取服务器端最新发表的几篇文章。
-
我们可以每次都重新获取,但这样费时又费流量。好的设计应该是我们把获取过的文章存下来,下次只获取最新发表的文章。
-
这样就有个问题,如果某一篇文章,我们已经获取过了,可有一天它更新了。。。。
- 还有个问题,文章持续获取下去,我们手机没空间了。。。。
-
如何使我们客户端能保存有限的文章,并且同时可以得到更新呢?
解决方法
1、文章表设计
- | index | content | ts | dl |
- index 索引;
- content 内容;
- ts 文章最后一次的修改时间。把ts的格式设计为:NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,即默认为当前的时间戳,且随着文章更改,自动更新为更改时间。
- dl 文章是否被删除了;
2、客户端查询文章时服务器端的工作
- 从session中查询该用户对文章的最后一次获取时间,last_gotten_ts;
- 如果有该记录,说明只需要给客户端发送last_gotten_ts只后的文章(
dl
!= 1 AND ts
> last_gotten_ts); - 如果没有该记录,表示是这个用户第一次获取,那发送最近的若干条文章(
dl
!= 1 ORDER BY index
DESC LIMIT 10)。 - 将session里的last_gotten_ts设置为结果集里最大的ts.
3、客户端查询到最新文章时的工作
- 根据接收到的文章,新增或更新本地缓存。这里使用REPLACE INTO更合适。同时,根据dl字段判断是否已经被删除,如果是,删除本地的文章;
- 删除过期的缓存文章;
- 展示文章列表,注意这里应该以index,而不是ts排序。这样保证文章是以创建时间排序,而非更新时间。
4、向前查询
- 这种情况适用于上拉列表时加载更多文章的功能。目标是获取某个文章之前的文章。因此客户端请求时,应该带着最后一条文章的index,服务器返回该index之前的若干文章。注意这时候,不应该存储last_gotten_ts。
5、为什么将last_gotten_ts存到session而不是数据库
- 我们也可以新建一个表。类似这样的结构: | user_index | last_gotten_ts | 但是这样会有如下两个问题:
- 用户在其它设备登录了,这时候服务器会以为是从老设备上请求的,只发送last_gotten_ts后的文章,导致两个设备相互干扰。
- 当客户端好长时间没有使用时,可能导致服务器这段时间累积的文章量比较大。而事实上当客户端再次使用时,客户端没必要全部接受,只需要接收最新的若干文章(就像第一次使用时那样)。
- 使用session则可以巧妙解决这两个问题。
- 两个设备相互干扰,显然不是我们希望的。而session是跟设备相关的,在服务器端每个设备有自己的session,这样的话相当于每个设备都相互独立,可以巧妙避开干扰。
- 如果我们把session的过期时间设置恰当,当客户端再次使用时,旧session已经过期。新的session里并没有任何查询历史。正如客户端第一次使用那样。这样就完美地解决了服务器端文章累积的问题。
6、客户端的文章“断层”
- 当客户端长时间不用,后面再使用时,因为没有全部获取,可能导致与缓存的老文章之间不连续,有“断层”。这样的话,如果用户再想加载更多文章时,可能我们的代码会跳过这个断层,直接加载老文章之前的文章。这样的话这个“断层”就没机会获取到了,丢失了。
- 如何解决这个问题呢?其实很简单,只要设置好客户端本地的过期期限即可。客户端每次启动,都检查是不是有缓存文章过期了,如果过期了,就删除之。很明显,这个时间期限不能大于服务器端的session的过期时间。
7、服务器端的文章的dl
字段
- 这个字段既然是删除的意思,那为什么不直接删除该记录呢?这个字段的实质目的,是要告诉客户端该记录被删除了。如果直接删除了该记录,客户端无从得知这个删除信息,那本地的缓存也就无法删掉。
- 如果已经被删了,还留在表里,是不是不太好?的确不好。服务器定期检查这些被删记录的删除时间(ts),如果超过一定期限了,那也删除之。注意这个期限不能小于客户端缓存的时间,即:保证在客户端删除了本地缓存记录之后,再删除该记录。
转载于:https://my.oschina.net/jiaozebo/blog/600010