我正在尝试编写一个 Python + SQLAlchemy 应用程序,它使用一个集中的 sqlite 数据库来存储有关各种文件的信息。我使用校验和来验证每个文件和/或文件版本在数据库中只存储一次,所以我UniqueConstraint
在校验和列上有一个。
我将文件信息存储在DbFile
要对其进行进一步操作的对象中。我创建了一个名为的静态方法New()
,它将返回一个DbFile
对象。如果文件已经存在于数据库中,它将返回该对象,否则将创建一个新对象。
import md5
# Not shown: sqlalchemy imports
Base = declarative_base()
engine = create_engine('sqlite:///test.db')
Session = sessionmaker(bind=engine)
session = Session()
class DbFile(Base):
id = Column(Integer, primary_key=True)
filename = Column(String, nullable=False)
checksum = Column(String, nullable=False)
__table_args__ = (UniqueConstraint('checksum'),)
@staticmethod
def New(filename):
file_md5 = md5.md5(open(filename).read())
checksum = file_md5.hexdigest()
q = session.query(Files).filter(Files.checksum == checksum)
if q.count() == 1:
print "Loading existing file object from database"
return q.one()
dbfile = DbFile(filename=filename, checksum=checksum)
在加载了一些文件后,我做了一个session.commit()
. 如果只有一个进程正在访问数据库,这很好用,但是如果我启动多个 python 进程(从命令行),其中一个总是会中止并sqlalchemy.exc.IntegrityError
抱怨校验和违反了唯一键约束。在检查存在和写入数据库之间显然存在竞争条件,但我还没有找到防止它的好方法。
我试图捕获错误,session.commit()
但有时错误是由q.count()
语句触发的。有没有一种干净的方法可以做到这一点?