Проблема с настройкой положения смещения myBatis для бесконечной прокрутки

Я создаю приложение, подобное 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.

Кто-нибудь может дать мне несколько предложений?

Спасибо, Питер

Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
0
737
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Общая идея состоит в том, чтобы вообще не использовать 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, является намного лучше с точки зрения производительности.

Другие вопросы по теме