Как предотвратить LockError в ZODB FileStorage при доступе к объектам ZODB через вызовы функций (один процесс) - PullRequest
0 голосов
/ 09 января 2019

У меня проблемы с ZODB LockError, но я считаю, что я работаю только с одним процессом на БД.

Моя цель для моего проекта состоит в том, чтобы иметь только две функции, load_project() и save_project(), которые позволяют пользователю загружать объект Project, работать с ним, а затем периодически сохранять его с save_project(), не имея пользователя взаимодействовать с ZODB напрямую. Вроде как они просто работают над документом и сохраняют на ходу.

Однако я заметил, что последовательно получаю LockError: я могу загрузить объект, сохранить объект один раз, но затем я получаю LockError всякий раз, когда пытаюсь сохранить его впоследствии. Очевидно, что я что-то сделал неправильно или не понимаю, как работает ZODB. Как я могу предотвратить это LockError?

Все другие проблемы LockError в SO, похоже, имеют дело с несколькими процессами. Я взаимодействую с кодом через Блокнот Jupyter, который, как я считаю, является всего лишь одним процессом. Когда я запускаю LockError, я могу перезапустить ядро ​​(запустив тем самым новый процесс), загрузить проект и затем сохранить его снова. Но тогда я не могу сохранить его во второй раз.

Вот код из двух функций, которые я импортирую из моего functions модуля:

def save_project(project: BIMProject):
    """
    Commits the project to the ZODB; including opening and closing the connection
    """
    if not hasattr(project, "filename"):
        project.filename = input("Enter a filename (without extension):")
    if not hasattr(project, "filepath"):
        tk_root = Tk()
        tk_root.withdraw()
        project.filepath = filedialog.askdirectory(title="Please select a directory")

    filename = project.filename
    full_path = project.filepath + "/" + filename

    storage=FileStorage(full_path)
    db=ZODB.DB(storage)
    connection=db.open()
    root=connection.root()
    if 'project' in root:
        root.update({'project': project})
    else:
        root['project'] = project # reassign to change
    transaction.commit()
    connection.close()

def load_project():
    """
    Loads a project from a database file
    """
    tk_root = Tk()
    tk_root.withdraw()
    filepath = filedialog.askopenfilename(title="Please select a database file")

    storage = FileStorage(filepath)
    db = ZODB.DB(storage)
    connection = db.open()
    root = connection.root()
    project = copy.deepcopy(root["project"])
    connection.close()
    db.close()
    return project

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 09 января 2019

Итак, после того, как в течение дня я ударился головой о стену, я прогулялся и решил, что вместо доступа к базе данных с помощью одних функций объект будет лучше подходить для поддержания соединения с хранилищем файлов и базой данных. Не совсем то, что я изображал, но отлично работает.

class LoaderSaver:
    """
    A 'hang around' object to use in conjunction with Project objects to save them
    in a ZODB FileStorage. Carries the ZODB storage, db, and connection objects once 
    they are opened.

    Only one Project file can be open at one time.
    """
    def __init__(self):
        self.storage = None
        self.db = None
        self.connection = None
        self.root = None

    def load(self):
        """
        Returns a Project object stored in a ZODB file storage. File selected by 
        user in a graphical 'file dialog' interface.
        """
        tk_root = Tk()
        tk_root.withdraw()
        filepath = filedialog.askopenfilename(title="Please select a database file")

        self.storage = FileStorage(filepath)
        self.db = ZODB.DB(self.storage)
        self.connection = self.db.open()
        self.root = self.connection.root()
        project = copy.deepcopy(self.root["project"])
        self.connection.close()
        return project

    def save(self, project: Project):
        """
        Commits the project to the ZODB
        """
        if not hasattr(project, "filename"):
            project.filename = input("Enter a filename (without extension):")
        if not hasattr(project, "filepath"):
            tk_root = Tk()
            tk_root.withdraw()
            project.filepath = filedialog.askdirectory(title="Please select a directory")

        filename = project.filename
        full_path = project.filepath + "/" + filename

        if not (self.storage and self.db):
            self.storage=FileStorage(full_path)
            self.db=ZODB.DB(self.storage)
        else:
            self.connection=self.db.open()
            self.root=self.connection.root()

        self.root['project'] = project
        transaction.commit()
        self.connection.close()
...