1

私は、ユーザーから映画のレビューを収集することを目的とした Sqlite DB を備えた単純な Django Web アプリを持っています。すべての映画は、正確に 2 人のレビュー担当者に見てもらい、レビューを提供することになっています。

2 件のレビュー/映画の要件を動的に実装するには、特定の映画を 3 人以上のログイン ユーザーに提示しないようにする必要があります。そうしないと、その映画に対して 2 つ以上のレビューが寄せられることになります。

したがって、レビューのために映画を送信する前に、まだ 2 人のレビュー担当者に送信されていないことを確認する必要があります。問題は、この情報をデータベースに保持すると、2 つ以上の同時要求で特定の映画を選択して、レビューのために送信することができます。これは、すべての要求が読み取り/取得操作を同時に実行したためです。

「SELECT FOR UPDATE」のようなものがあればいいのですが、残念ながらSQLiteではサポートされていません。

誰にもアイデアはありますか?前もって感謝します。

4

1 に答える 1

0

トランザクションを使用して問題を解決できると思います。適切な django のドキュメントは次のとおりです。例を次に示します。

2 つの同時トランザクションが同じ sqlite DB に書き込もうとすると、「OperationalError: database is locked」がスローされるようです。おそらく Django ORM (リンクを参照) を使用したいと思うでしょうが、アイデアを示すためのハックな例を次に示します。

import sqlite3
# 2 connections, 2 cursors
con = sqlite3.connect('test.db', isolation_level=None)
con2 = sqlite3.connect('test.db', isolation_level=None)
cur = con.cursor()
cur2 = con2.cursor()

# create really simple table
try:
    cur.execute("CREATE TABLE MOVIES(id INTEGER PRIMARY KEY, r1 INTEGER, r2 INTEGER)")
    cur.execute("INSERT INTO MOVIES(id,r1, r2) VALUES (1,0,0)")
    cur.execute("INSERT INTO MOVIES(id,r1, r2) VALUES (2,0,0)")
except:
    pass

# awkward read/write split mid-transaction is purely for demonstration purposes..
def read(cursor):
    cursor.execute("BEGIN IMMEDIATE TRANSACTION")  # get write lock straight away
    data = cursor.execute("SELECT * FROM MOVIES WHERE r1 == 0 OR r2 == 0")
    return data.fetchall()

def write(cursor, movie_id, reviewer_column, new_reviewer_id):
    cursor.execute("UPDATE MOVIES SET %s=%d WHERE id == %d AND %s ==0" % (
        reviewer_column, new_reviewer_id, movie_id, reviewer_column))
    cursor.execute("COMMIT")

# works fine
data1 = read(cur) # [(1, 0, 0), (2, 0, 0)]
write(cur, data1[0][0], "r1", 123)

# now we have concurrent access..
data1 = read(cur) # [(1, 123, 0), (2, 0, 0)]
data2 = read(cur2) # throws OperationalError: database is locked.
# the second thread should probably wait a bit before retrying.

# in the mean time..
write(cur, data1[0][0], "r2", 456) #works

# now it's safe for the second thread to retry
data2 = read(cur2) # [(2, 0, 0)]
write(cur2, data2[0][0], "r1", 457) #works

上記の後のデータ:

# MOVIES
# id |  r1 |  r2
#  1 | 123 | 456
#  2 | 457 |   0

これにより、DB に意味のないものを配置することはできなくなりますが、即時書き込みロックは、そこに到達するためのやや粗雑な方法です。

于 2013-02-03T01:27:45.773 に答える