【问题标题】:python sqlite3, how often do I have to commit?python sqlite3,我必须多久提交一次?
【发布时间】:2016-03-27 03:31:40
【问题描述】:

我有一个 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()

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

【问题讨论】:

    标签: python sql sqlite


    【解决方案1】:

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

    并发读者看到什么

    这是每个人第一眼看到的:当对数据库的更改被提交时,它对其他连接变得可见。除非它被提交,否则它只会在本地对进行更改的连接保持可见。由于sqlite 的并发特性有限,只能在事务打开时读取数据库。

    您可以通过运行following script 并调查其输出来调查发生了什么:

    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()
    

    输出:

    $ 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)]
    $
    

    因此,这取决于您是否可以忍受当前阅读器(无论是在同一个脚本中还是在另一个程序中)有时会落后两个的情况。

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

    性能

    数据库更改的性能很大程度上取决于您如何进行更改。它已经被标注为FAQ:

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

    了解此处的详细信息绝对有帮助,因此请随时关注link 并深入了解。另请参阅此awsome analysis。它是用 C 语言编写的,但结果与 Python 中的结果相似。

    注意:虽然这两个资源都引用了 INSERT,但对于相同的参数,UPDATE 的情况将非常相似。

    独占锁定数据库

    正如上面已经提到的,一个打开的(未提交的)事务将阻止来自并发连接的更改。因此,通过执行它们并共同提交所有这些更改,将数据库的许多更改捆绑到单个事务中是有意义的。

    不幸的是,有时计算更改可能需要一些时间。当并发访问是一个问题时,您不会希望将数据库锁定那么长时间。因为以某种方式收集待处理的 UPDATE 和 INSERT 语句会变得相当棘手,这通常会让您在性能和排他锁定之间进行权衡。

    【讨论】:

    • 如果他让他的电脑通宵运行插入数据,但忘记提交,并且电脑在晚上自动关闭,当他下次进来的时候早上提交会不会太迟了?天,还是他必须重新开始工作?
    • 未提交的更改当然会丢失。信息是提交是有代价的,你必须提前评估如何处理它。当中断频繁发生时,SQL 数据库甚至可能不是您需要的主存储。
    • SQLite 库是否将未提交的更改存储在 RAM 中,并在提交时先将其写入磁盘?
    猜你喜欢
    • 2019-07-27
    • 1970-01-01
    • 2015-07-02
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多