Python 持续检查Pyside2上的SQLAlchemy数据库连接

Python 持续检查Pyside2上的SQLAlchemy数据库连接,python,qt,sqlalchemy,pyqt5,pyside2,Python,Qt,Sqlalchemy,Pyqt5,Pyside2,首先,我想弄清楚如何每秒检查数据库状态。这样用户就可以知道数据库是否已启动,而无需单击或触发任何操作。我已经读到,这将产生评论中提到的问题 下面是我的最小可重复性示例: import sys import os import shiboken2 from PySide2 import QtCore, QtGui, QtWidgets from PySide2.QtWidgets import QMainWindow, QFileDialog, QMessageBox, QWidget, QDia

首先,我想弄清楚如何每秒检查数据库状态。这样用户就可以知道数据库是否已启动,而无需单击或触发任何操作。我已经读到,这将产生评论中提到的问题

下面是我的最小可重复性示例:

import sys
import os
import shiboken2
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtWidgets import QMainWindow, QFileDialog, QMessageBox, QWidget, QDialog, QProxyStyle
from sqlalchemy import create_engine, inspect

class MyWidget(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.resize(200, 200)
        self.path = os.path.abspath(os.path.dirname(sys.argv[0]))
        self.button = QtWidgets.QPushButton("Open File")
        self.labelFile = QtWidgets.QLabel("empty")
        self.labelData = QtWidgets.QLabel("None")
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.button)
        self.layout.addWidget(self.labelFile)
        self.layout.addWidget(self.labelData)
        self.setLayout(self.layout)
        self.button.clicked.connect(self.open_file)
        self.process = None
        self.CreateEngine = CreateEngine(self)
        self.CreateEngine.result.connect(self.start_timer)
        self.CreateEngine.start()

    def open_file(self):
        x = QFileDialog.getOpenFileName(self,"Just To Spice This Code",self.path,"CSV Files (*.csv)")
        self.labelFile.setText(x[0]) #just to check that GUI doesn't freeze

    def start_timer(self,engine): #callback from CreateEngine
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(lambda: self.continuously_check(engine))
        self.timer.start(1000) #check connetion every second, as real-time as possible

    def continuously_check(self,engine): #this gonna get called every second, yes it isn't effective i know       
        self.process = CheckConnection(self,engine)
        self.process.result.connect(self.update_connection_label)
        self.process.start()

    def update_connection_label(self,x): #update connection status on GUI
        self.labelData.setText("DB Status: "+str(x))

    def closeEvent(self,event): #to handle QThread: Destroyed while thread is still running
        print("begin close event")
        if(self.process is not None):
            if(shiboken2.isValid(self.process)): #to check whether the object is deleted. ->
                self.process.wait()             #-> this will get messy when the DB connection is down 
                self.process.quit()            #-> (IMO):since i stack so many CheckConnection objects maybe?
        print("end close event")

class CreateEngine(QtCore.QThread): #creating engine on seperate thread so that it wont block GUI
    result = QtCore.Signal(object)
    def __init__(self, parent):
        QtCore.QThread.__init__(self, parent)
        self.engine = None
    def run(self):
        self.engine = create_engine('mysql+pymysql://{}:{}@{}:{}/{}'.format("root","","localhost","3306","adex_admin"))
        self.result.emit(self.engine)

class CheckConnection(QtCore.QThread): #constantly called every second, yes its not a good approach ->
    result = QtCore.Signal(str) #-> i wonder how to replace all this with something appropriate
    def __init__(self, parent,engine):
        QtCore.QThread.__init__(self, parent)
        self.engine = engine
    def run(self):
        try:
            self.engine.execute('SELECT 1').fetchall()
            self.result.emit("Connected")
        except:
            self.result.emit("Not Connected")
        self.deleteLater() #somehow this doesn't do it job very well. maybe blocked?
        #-> especially when the connection is busted. this thread gets stuck quite long to finish
if __name__ == "__main__":
    #idk why when you start this without connection it's running really slow on showing the status of DB
    #you must wait like 4 seconds until the connection status is showed up, which is really bad
    #but once it's live. it could read database status really fast
    app = QtWidgets.QApplication(sys.argv)
    widget = MyWidget()
    widget.show()
    sys.exit(app.exec_())
我创建这个示例只是为了重现我在真实应用程序中面临的相同问题。因此,问题在于closeEvent花费太长时间来终止检查过程,并阻塞GUI。我创建“closeEvent”的原因是,当应用程序关闭时,我有一个生成[QThread:Destroyed while thread is live running]的事件

此外,当数据库不可访问时,它会使QThread完成的时间比它应该完成的时间长,这与数据库可访问时不同。但是我们可以像我们想要的那样检索状态(实时数据库状态的每一秒)。我也尝试过这种愚蠢的方法

...
    def continuously_check(self,engine):
        self.process = CheckConnection(self,engine)
        self.process.result.connect(self.update_connection_label)
        self.process.finished.connect(lambda: QtCore.QTimer.singleShot(1000,self.continuously_check))
        self.process.start()
...
希望它不会在线程完成之前继续创建对象(ps:显然这不起作用)。那么,在这个问题上,最好的方法是什么?很抱歉,一次出现多个问题。

因此我故意尝试执行“非SQL”异常(例如,通过提供未定义的变量故意创建错误),但线程处理得非常好。所以我认为是SQLAlchemy阻止了线程异常处理,所以我故意尝试了一个“非SQL”异常(例如,通过给出未定义的变量故意创建错误),但线程处理得非常好。所以我认为是SQLAlchemy阻止了线程异常处理