データベース内のデータの動的な追加と削除により、ページング クエリ データの重複または欠落が発生する問題の分析と解決策

1. 問題分析

1. データのリクエスト

    通常の状況では、サーバーへの負荷を軽減したり表示を容易にするために、フロントエンドはページングを通じてデータを要求し、API インターフェイスを呼び出すときにパラメータ page と pageSize が取得されます。たとえば、あるクラスの生徒データをリクエストし、登録時間の逆順に並んでいると仮定して、最初のページにある 10 人の生徒のデータを取得します。

https://api.domain.com/class/student/list?page=1&pageSize=10

    ページネーション クエリは、SQL の制限ステートメント、使用量の制限によって実現されます。

select * from table_name 制限 [オフセット,] 行


offset: 最初のレコード行のオフセット (つまり、どの行から返すか) を指定します。注意: 最初の行のオフセットは 0 です。
rows: 特定の行数を返します。

    データの最初のページを要求します。ページ = 1、オフセットは (1 - 1) * 10、つまり 0 に等しくなります。

select * from tb_student order by register_time desc 制限 0、10;

    データの 2 ページ目を要求します。ページ = 2、オフセットは (2 - 1)*10、つまり 10 に等しくなります。

select * from tb_student order by register_time desc limit 10, 10;

2. データの重複または欠落

    1ページ目のデータを取得したとして、2枚目のデータを要求する前にバックグラウンドで新規生徒が新規登録されており、登録時刻の逆順に並べると、この新規登録生徒が1番目のデータとなります。これは「スタック」方式です。理解するには、新しいデータの挿入により、元の最初のページの最後のデータ部分が、2 番目のページの最初のデータの位置に PUSH されます。 2 ページ目のデータは、元の 1 ページ目のデータの最後のレコードまで「繰り返し」取得されます。これが発生すると、フロントエンドは通常、隣り合った同一の 2 つの生徒データを表示します

    同様に、2 ページ目のデータを取得する前に、1 ページ目の生徒がログアウトによりデータベースから削除され、すべてのデータの開始位置オフセットが 1 減らされ、最初のデータが2 ページ目 これは最初のページの最後のデータになるため、2 ページ目のデータを要求したときに返される結果には、このデータが「欠落」します。

概要: データベースのデータが動的に変化する場合、オフセットにリアルタイムの動的補正がなく、依然として offset = (page - 1) * pageSize の方法を使用してデータを取得すると、データの重複または欠落が発生します。

2、解決策

    上記の分析の後、データをリクエストするたびに、正しいオフセットが取得できれば、異議申し立ては行われないことがわかります。このオフセットは、リクエストされた学生データの最初のページの最後の学生レコードである必要があります。「の位置逆順に並べ替えます。」したがって、最後のレコードの ID を取得し、パラメーター「 fromId = ID 」を通じてバックグラウンドによって提供されるインターフェースにアップロードし、計算を通じてデータの次のページを要求するための正しいオフセットを取得します。データベースのデータが追加または削除されても、重複や欠落は発生しません。一般に、データが要求されるたびに、formIId で表されるレコードの次のレコードから開始して 10 個の新しいレコードが取得されます。

    データの最初のページを要求します (fromId = 0)。

https://api.domain.com/class/student/list?fromId=0&pageSize=10

    fromId = 0、つまりデータの最初のページをリクエストすることを意味するため、オフセット値は 0 であることに同意します。データの最初のページの最後のデータの Student_id を 1001 と仮定します。

    パラメーター fromId = 1001 を使用して、データの 2 ページ目を要求します。

https://api.domain.com/class/student/list?fromId=1001&pageSize=10

    最後のレコード (fromId) の後の次のレコードの開始位置を取得するためのバックグラウンドでのリアルタイム計算:

select count(*) from tb_student where register_time >= (select register_time from tb_student where students_id = 1001);


予防:

1. ステートメント内にネストされた選択クエリがあり、内側のネストされたクエリ ステートメントは 1 つのレコードのみを返すことができ、複数のレコードを表示することはできません。そうでない場合は、SQL の実行後にエラーがスローされます。

2. 登録時刻で昇順にソートする場合、「 >= 」を「 <= 」に置き換えます

3. ソートに使用されるフィールド register_time は、同じ値を持つことはできません。同じ値を持たないと、クエリ データが欠落する可能性があります (たとえば、11 番目のデータと 10 番目のデータの register_time の値が同じである場合、上記の SQL ステートメントを実行して得られるオフセット値)その場合、第 11 条のデータが 2 ページ目で要求されたデータに表示されなくなります)。

    上記の SQL クエリ ステートメントによって返された値をオフセットとして使用して、学生データの 2 ページ目を要求します。クエリ ステートメントは次のとおりです。

select * from tb_student order by register_time desc limit [offset,] 10;

おすすめ

転載: blog.csdn.net/crazestone0614/article/details/132346462