Python Sqlite3数据库锁定,QWidget

时间:2016-02-20 00:48:48

标签: python database sqlite pyqt4

当我尝试从pyqt小部件更新数据库时,我得到sqlite3.OperationalError: database is locked

主窗口显示数据库中的项目列表。 双击项目时,将弹出一个小部件,其中包含修改数据库同一行中的值的选项。

我有4个单独的.py文件; (我删除了大部分代码)

DBmanager.py,其中包含与数据库交互的所有函数。

class DatabaseUtility:
        def __init__(self, databaseFile):
        self.db = databaseFile 
        self.conn = sqlite3.connect(self.db)
        self.c = self.conn.cursor()  

    def ChangeItemQuantity(self, itemName, incramentQuantity):
        try:
            # Change given item quantity in database
            self.c.execute('''
                 SELECT quantity
                 FROM items
                 WHERE itemName=?
                 ''',(itemName,))
            print(itemName)
            print(incramentQuantity)
            current_quantity = self.c.fetchone()
            print(current_quantity[0])
            new_quantity = current_quantity[0] + incramentQuantity
            self.c.execute('''
                 UPDATE items
                 SET quantity = ?
                 WHERE itemName=?
                 ''',(new_quantity, itemName))
            self.conn.commit()
        except Exception as error:
            # Rollback any changes if something goes wrong.
            self.conn.rollback()
            raise error

    def __del__(self):
        """Commit and close database connection when the class is terminated."""
        # pass
        self.conn.commit()
        self.c.close()
        self.conn.close()

StartGui.py包含GUI的功能。

import sys
from PyQt4 import QtCore, QtGui
from guiFormat import Ui_MainWindow
from itemWidget import Ui_itemWidget
from DBmanager import DatabaseUtility


class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.db = 'testdb.db'
        self.dbUtil = DatabaseUtility(self.db)
        self.ui.updateButton.clicked.connect(self.populateTable_default)
        self.ui.updateButton.clicked.connect(self.dbUtil.UpdateDatabase)
        self.ui.searchButton.clicked.connect(self.populateTable_search)
        self.ui.tableWidget.doubleClicked.connect(self.open_item_widget)
        self.ui.tableWidget.resizeRowsToContents()

        # Populate table on initial startup
        self.populateTable_default()

    def open_item_widget(self):
        self.item_widget = ItemWidget(self)
        # self.item_widget.show()
        column_count = self.ui.tableWidget.columnCount()
        self.item_widget.ui.tableWidget.setColumnCount(column_count)
        self.item_widget.ui.tableWidget.setRowCount(1)
        column_names = self.dbUtil.GetColumns('items')
        self.item_widget.ui.tableWidget.setHorizontalHeaderLabels(column_names)
        row = self.ui.tableWidget.currentRow()
        for column in range(column_count):
            x = self.ui.tableWidget.item(row, column).text()
            item_data = QtGui.QTableWidgetItem(str(x))
            self.item_widget.ui.tableWidget.setItem(0, column, item_data)
        self.item_widget.show()


class ItemWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        self.db = 'testdb.db'
        self.dbUtil2 = DatabaseUtility(self.db)
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_itemWidget()
        self.ui.setupUi(self)
        self.ui.cancelOkButtonBox.rejected.connect(self.close)
        self.ui.cancelOkButtonBox.accepted.connect(self.submit_changes)

    def submit_changes(self):
        # Get item Name.
        item_name = self.ui.tableWidget.item(0,0).text()
        # Get number from increment box.
        quant_increment = self.ui.QuantSpinBox.value()
        alert_incrament = self.ui.alertSpinBox.value()
        print('Changing quantity...', item_name, quant_increment)
        self.dbUtil2.ChangeItemQuantity(item_name, quant_increment)

        self.close()



##======================================================================================================================
##======================================================================================================================
if __name__ == "__main__":
    dbUtil = DatabaseUtility('testdb.db')
    app = QtGui.QApplication(sys.argv)
    mainwindow = MainWindow()
    mainwindow.show()
    # itemwidget = ItemWidget()
    # itemwidget.show()
    sys.exit(app.exec_())

Mainwindow.py是来自pyqt设计器的主窗口导出。

Itemwidget.py也是来自项目小部件的pyqt设计器的导出。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

sqlite3文档说:

  

当多个连接访问数据库时,其中一个连接   进程修改数据库,SQLite数据库被锁定,直到   该交易已经提交。

由于您有两个连接,一个由MainWindow打开,另一个由ItemWidget打开,一个可能导致问题的原因正是文档所说的。一个连接尝试在未提交其他连接所做的更改时更新数据库。使用的ChangeItemQuantity方法不会发生这种情况,因为它所做的更改会立即提交,但显然DatabaseUtility还有其他方法,例如UpdateDatabase。如果他们进行了未立即提交的更改,则可能是问题所在。

MainWindowItemWidget共享一个连接,看看问题是否消失。您可以通过conn DatabaseUtility个实例的共享属性来完成此操作,而不会更改来电者:

class DatabaseUtility:

    conn = None

    def __init__(self, databaseFile):
        self.db = databaseFile
        if self.__class__.conn is None:
            self.__class__.conn = sqlite3.connect(self.db)
        self.c = self.conn.cursor()

此外,尽管这似乎不太可能成为问题,但如果某个其他进程在同一个SQLite数据库上有一个打开的事务,则只要该事务处于活动状态,数据库就会被锁定。有些应用程序有养成看似活跃交易的坏习惯。每当我用SQLite Browser打开一个数据库时,我都无法对其他程序的数据库做任何事情(也许我可以关闭它,但我从不打算弄清楚如何...)