myBatis无限滚动的偏移位置设置问题

时间:2018-08-07 04:29:58

标签: mysql spring-boot mybatis spring-mybatis

我正在构建类似Quora的应用程序。后端使用spring boot mybatis连接到mysql数据库。当用户打开网站时,后端将返回前10个问题。如果用户单击“获取更多”按钮,则后端应返回接下来的10个问题。

mybatis代码是

<mapper namespace="com.quora.dao.QuestionDAO">
    <sql id="table">question</sql>
    <sql id="selectFields">id, title, content, comment_count,created_date,user_id
    </sql>
    <select id="selectLatestQuestions" resultType="com.quora.model.Question">
        SELECT
        <include refid="selectFields"/>
        FROM
        <include refid="table"/>

        <if test="userId != 0">
            WHERE user_id = #{userId}
        </if>
        ORDER BY id DESC
        LIMIT #{offset},#{limit}
    </select>
</mapper>

当前,我的逻辑是第一次#{offset}为0,第二次#{offset}为10。但是我发现当表频繁更新时,这种逻辑是不正确的。如果表已插入新行,则用户可能会得到重复的数据。如何根据前端显示的最后一个问题ID设置#{offset}?例如,前端的最后一个问题ID是10,那么#{offset}应该是问题ID 10的行号。

有人可以给我一些建议吗?

谢谢, 彼得

1 个答案:

答案 0 :(得分:0)

通常的想法是根本不使用OFFSET而是进行过滤。如果您可以定义消息的顺序,以便在插入新消息时它不会改变(例如,您递增生成ID并按id ASC对消息进行排序),那么这很容易:

SELECT id, some_other_field, yet_another_field
FROM question
<if test="last_seen_question_id != null">
    WHERE id > #{last_seen_question_id}
</if>
ORDER BY id ASC
LIMIT #{limit}

然后,客户端应使用最近看到的问题ID,并在希望获取下一页时将其传递。

根据您的查询(ORDER BY id DESC),您似乎想在顶部看到最新的问题。这是一个问题,因为新插入的问题将趋于首位。

如果您可以先在下一页提出新问题,然后再提出较旧的问题,可以这样:

<!-- This condition is needed to avoid duplication when the first page is fetched
     and we haven't seen any question yet.
     In this case we just get up to limit of the last questions.
-->
<if test="newest_seen_question_id != null">
SELECT * FROM (
  -- select all questions that were created _after_
  -- the last seen max question id
  -- client should maintain this value as in get the 
  -- largest question id for every page and compare it
  -- with the current known max id. And client should
  -- do it for the whole duration of the paging
  -- and pass it to the follow up queries
  SELECT id, some_other_field, yet_another_field
  FROM question
  WHERE id > #{newest_seen_question_id}
  -- note that here we do sorting in the reverse order
  -- basically expanding the set of records that was returned
  -- in the direction of the future
  ORDER BY id ASC
  LIMIT #{limit}
  UNION ALL
</if>
  -- select all questions that were created _before_
  -- the last seen min question id.
  -- client should maintain this value for the whole
  -- duration of the paging
  -- and pass it to the follow up queries      
  SELECT id, some_other_field, yet_another_field
  FROM question
  <if test="oldest_seen_question_id != null">
    WHERE id < #{oldest_seen_question_id}
  </if>
  ORDER BY id DESC
  LIMIT #{limit}
<if test="newest_seen_question_id != null">
) AS q
ORDER BY id DESC
LIMIT #{limit}
</if>

另一个好处是,从性能的角度来看,这种不使用OFFSET的分页方法是much better