Я создаю приложение, подобное Quora. Бэкэнд использует весеннюю загрузку, 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. Но я считаю, что эта логика неверна, когда таблица часто обновляется. Пользователь может получить повторяющиеся данные, если в таблицу были вставлены новые строки. Как я могу установить # {offset} на основе последнего идентификатора вопроса, показанного в интерфейсе? Например, последний идентификатор вопроса во внешнем интерфейсе равен 10, тогда # {смещение} должно быть номером строки вопроса с идентификатором 10.
Кто-нибудь может дать мне несколько предложений?
Спасибо, Питер






Общая идея состоит в том, чтобы вообще не использовать OFFSET и вместо этого выполнить фильтрацию. Если вы можете определить порядок сообщений так, чтобы он не менялся при вставке новых сообщений (например, вы постепенно генерируете идентификаторы и сортируете сообщения с помощью 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}
Затем клиент должен использовать идентификатор последнего просмотренного вопроса и передать его, когда он хочет получить следующую страницу.
Судя по вашему запросу (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, является намного лучше с точки зрения производительности.