使用python sqlite在同一事务中选择并更新

时间:2014-12-17 14:52:59

标签: python multithreading sqlite

我想用Python在同一个sqlite3数据库上用select和update查询做一个事务,以确保没有其他线程可以在我没有用第一个线程完成更新查询时进行选择。

基础非常简单,需要完成一系列工作,我想确保多个线程无法获得相同的工作ID。

with sqlite3.connect('database.sqlite') as db:
    db_cursor = db.cursor()
    db_cursor.execute("SELECT id FROM mytable WHERE status=?", 'todo')
    myrow = db_cursor.fetchone()
    if myrow :
        id = myrow[0]
        db_cursor.execute("UPDATE mytable SET status=? WHERE id=?", ['done', id])
        # id is used after that.

隔离级别参数会成为解决方案吗?在我释放连接时,隔离是否有效,或者仅在" fetchone"功能

感谢。

1 个答案:

答案 0 :(得分:0)

你当然可以在这里使用锁定或交易,但你可能并不真的需要这些。

只要确保作业仍然可用:

with sqlite3.connect('database.sqlite') as db:
    while 1:
        db_cursor = db.cursor()
        db_cursor.execute("SELECT id FROM mytable WHERE status=?", 'todo')
        # ^^^^^^^ Consider adding LIMIT 1 here, you don't need all rows if you only
        # use one.

        myrow = db_cursor.fetchone()
        if not myrow :
            break

        id, = myrow
        accepted = db_cursor.execute("UPDATE mytable SET status=? WHERE id=? AND status=?", ['done', id, 'todo']) 
        # ^^^^^^ This will return the number of rows updated. 
        # Note that we only update if the status is still 'todo', so if we get 1 updated 
        # row, we're sure no one else took our job. This works because UPDATE is atomic.

        # A performance improvement would be to select multiple rows above, 
        # and try another one (maybe at random) if you didn't get your "first pick"

        if not accepted: 
            # Whoops this job was taken! Try again and get another one
            continue

        # This job is yours, do your thing!

请注意,在高争用情况下,这可能效果不佳。像往常一样:首先尝试一个简单的解决方案,一旦确定瓶颈就进行迭代(在您的情况下:迭代意味着使用实际的任务代理)。