python sqlite3,我多久要提交一次?

del*_*lta 14 python sql sqlite

我有一个for循环,它使用我编写的sqlite管理器类对数据库进行了许多更改,但我不确定我多久需要提交...

for i in list:
    c.execute('UPDATE table x=y WHERE foo=bar')
    conn.commit()
    c.execute('UPDATE table x=z+y WHERE foo=bar')
    conn.commit()
Run Code Online (Sandbox Code Playgroud)

基本上我的问题是我是否必须在那里调用两次提交,或者我是否可以在完成两次更改后调用它一次?

fla*_*ier 27

是否conn.commit()在每次数据库更改后的过程结束时调用一次取决于几个因素.

并发读者看到了什么

这是每个人第一眼就想到的:当提交对数据库的更改时,它对其他连接变得可见.除非提交,否则它仅在本地可见,用于进行更改的连接.由于有限的并发功能sqlite,数据库只能在事务打开时读取.

您可以通过运行以下脚本并调查其输出来调查发生的情况:

import os
import sqlite3

_DBPATH = "./q6996603.sqlite"

def fresh_db():
    if os.path.isfile(_DBPATH):
        os.remove(_DBPATH)
    with sqlite3.connect(_DBPATH) as conn:
        cur = conn.cursor().executescript("""
            CREATE TABLE "mytable" (
                "id" INTEGER PRIMARY KEY AUTOINCREMENT, -- rowid
                "data" INTEGER
            );
            """)
    print "created %s" % _DBPATH

# functions are syntactic sugar only and use global conn, cur, rowid

def select():
    sql = 'select * from "mytable"'
    rows = cur.execute(sql).fetchall()
    print "   same connection sees", rows
    # simulate another script accessing tha database concurrently
    with sqlite3.connect(_DBPATH) as conn2:
        rows = conn2.cursor().execute(sql).fetchall()
    print "   other connection sees", rows

def count():
    print "counting up"
    cur.execute('update "mytable" set data = data + 1 where "id" = ?', (rowid,))

def commit():
    print "commit"
    conn.commit()

# now the script
fresh_db()
with sqlite3.connect(_DBPATH) as conn:
    print "--- prepare test case"
    sql = 'insert into "mytable"(data) values(17)'
    print sql
    cur = conn.cursor().execute(sql)
    rowid = cur.lastrowid
    print "rowid =", rowid
    commit()
    select()
    print "--- two consecutive w/o commit"
    count()
    select()
    count()
    select()
    commit()
    select()
    print "--- two consecutive with commit"
    count()
    select()
    commit()
    select()
    count()
    select()
    commit()
    select()
Run Code Online (Sandbox Code Playgroud)

输出:

$ python try.py 
created ./q6996603.sqlite
--- prepare test case
insert into "mytable"(data) values(17)
rowid = 1
commit
   same connection sees [(1, 17)]
   other connection sees [(1, 17)]
--- two consecutive w/o commit
counting up
   same connection sees [(1, 18)]
   other connection sees [(1, 17)]
counting up
   same connection sees [(1, 19)]
   other connection sees [(1, 17)]
commit
   same connection sees [(1, 19)]
   other connection sees [(1, 19)]
--- two consecutive with commit
counting up
   same connection sees [(1, 20)]
   other connection sees [(1, 19)]
commit
   same connection sees [(1, 20)]
   other connection sees [(1, 20)]
counting up
   same connection sees [(1, 21)]
   other connection sees [(1, 20)]
commit
   same connection sees [(1, 21)]
   other connection sees [(1, 21)]
$
Run Code Online (Sandbox Code Playgroud)

所以这取决于你是否能够忍受这样一种情况:一个当前的阅读器,无论是在同一个剧本中还是在另一个程序中,它有时会被两个人关闭.

当要进行大量更改时,另外两个方面将进入场景:

性能

数据库更改的性能在很大程度上取决于您的操作方式.它已作为常见问题解答:

实际上,SQLite很容易在普通的台式计算机上每秒执行50,000或更多INSERT语句.但它每秒只会进行几十次交易.[...]

了解这里的细节绝对有帮助,所以不要犹豫,请关注链接并深入了解.另请参阅此详细分析.它是用C语言编写的,但结果与Python中的结果相似.

注意:虽然两个资源都引用INSERT,但UPDATE对于相同的参数,情况将大致相同.

专门锁定数据库

如上所述,open(未提交)事务将阻止并发连接的更改.因此,通过执行它们并共同提交整个数据库,将许多更改捆绑到单个事务中是有意义的.

不幸的是,有时,计算更改可能需要一些时间.当并发访问是一个问题时,您不希望长时间锁定您的数据库.因为以某种方式收集挂起UPDATEINSERT语句会变得相当棘手,这通常会让你在性能和独占锁定之间进行权衡.

  • 未提交的更改当然会丢失。这里传达的信息是,承诺是有代价的,你必须提前评估如何处理它。当中断频繁时,SQL 数据库甚至可能不是您所需的主存储。 (2认同)