在Python中编写非DB代码的事务

时间:2017-07-19 21:04:29

标签: python file transactions rollback

一段python代码正在编写/创建多个文件。 我想把它放在事务处理方式中,所以如果其中一个文件的创建失败,所有内容都会回滚。这将有助于节省硬盘空间并避免因失败的事务而导致无用的文件。

具体,通过向我的python服务器发送图片:

  1. 首先保存原始文件,完整分辨率
  2. 创建较小版本的图片
  3. 保存此较小的版本
  4. 交易成功
  5. 然而,第2步或第3步可能由于某种原因而失败。如何回滚第1步?

    解决方案应该是通用的,因为可能会有更多步骤。

    Python中是否存在常见的事务处理技巧?

1 个答案:

答案 0 :(得分:0)

我的解决方案

它将在系统的默认临时目录(在Linux上为/tmp)中创建一个临时目录,并返回一个pathlib.Path对象,您可以在其中写入文件,如果一切成功,则最终会将内容移动到目的地,即使没有,也不会发生。

这两种方法都可以在清除后清除并删除已写入临时目录的数据

import tempfile
import shutil
from typing import ContextManager, Union
from pathlib import Path
from contextlib import contextmanager

@contextmanager
def transactional_mkdir(destination: Union[str, Path], overwrite: bool = False) -> ContextManager[Path]:
    """
    Create a directory and get reference to it, while inside the context if any unhandled failure is met all the writing
    operations that were made to the directory will be undone

    :param destination: Destination directory to write create
    :param overwrite: If True, will overwrite destination if it exists 
    :return: Path object to destination directory
    """

    # Validate input
    destination = Path(destination)
    if not overwrite and destination.exists():
        raise FileExistsError(f'destination already exists. To overwrite use "overwrite=True"')

    # Create temporary directory
    temp_dir = Path(tempfile.mkdtemp())

    try:
        yield temp_dir  # Give control

        # Remove existing
        if destination.exists():
            if destination.is_dir():
                shutil.rmtree(destination)  # Remove directory
            else:
                destination.unlink()  # Remove file

        # Save to destination
        shutil.move(temp_dir, destination)

    finally:
        shutil.rmtree(temp_dir)  # Remove directory