Ứng dụng của tôi đang sử dụng phiên scoped và kiểu khai báo của SQLALchemy. Đó là một ứng dụng web và rất nhiều lần chèn DB được thực thi bởi Celery
, một công cụ lên lịch tác vụ.Xử lý các khóa chính trùng lặp khi chèn trong SQLAlchemy (kiểu khai báo)
Thông thường, khi quyết định để chèn một đối tượng, mã của tôi có thể làm điều gì đó dọc theo dòng sau đây:
from schema import Session
from schema.models import Bike
pk = 123 # primary key
bike = Session.query(Bike).filter_by(bike_id=pk).first()
if not bike: # no bike in DB
new_bike = Bike(pk, "shiny", "bike")
Session.add(new_bike)
Session.commit()
Vấn đề ở đây là vì có rất nhiều này được thực hiện bởi người lao động không đồng bộ, nó có thể cho một làm việc ở nửa chừng mặc dù chèn Bike
với id=123
, trong khi một số khác đang kiểm tra sự tồn tại của nó. Trong trường hợp này, nhân viên thứ hai sẽ thử và chèn một hàng có cùng khóa chính và SQLAlchemy sẽ tăng IntegrityError
.
Tôi không thể cho cuộc sống của tôi tìm thấy một cách tốt đẹp để đối phó với vấn đề này ngoài việc trao đổi ra Session.commit()
cho:
'''schema/__init__.py'''
from sqlalchemy.orm import scoped_session, sessionmaker
Session = scoped_session(sessionmaker())
def commit(ignore=False):
try:
Session.commit()
except IntegrityError as e:
reason = e.message
logger.warning(reason)
if not ignore:
raise e
if "Duplicate entry" in reason:
logger.info("%s already in table." % e.params[0])
Session.rollback()
Và sau đó ở khắp mọi nơi tôi có Session.commit
bây giờ tôi có schema.commit(ignore=True)
nơi tôi don' Hãy nhớ rằng hàng không được chèn lại.
Đối với tôi, điều này có vẻ rất dễ vỡ do kiểm tra chuỗi. Cũng như một FYI, khi một IntegrityError
được nâng lên nó trông như thế này:
(IntegrityError) (1062, "Duplicate entry '123' for key 'PRIMARY'")
Vì vậy, tất nhiên là chìa khóa chính tôi đã chèn được cái gì đó như Duplicate entry is a cool thing
sau đó tôi cho rằng tôi có thể bỏ lỡ IntegrityError
's mà không thực sự vì các khóa chính trùng lặp.
Có bất kỳ phương pháp tốt hơn, mà duy trì cách tiếp cận SQLAlchemy sạch Tôi đang sử dụng (như trái ngược với bắt đầu để viết ra báo cáo trong chuỗi vv..)
Db là MySQL (mặc dù cho kiểm tra đơn vị tôi thích để sử dụng SQLite và không muốn cản trở khả năng đó với bất kỳ phương pháp tiếp cận mới nào).
Chúc mừng!
tại sao bạn không xem xét sử dụng tự động tăng để tạo ra bạn khóa chính? thì bạn không phải lo lắng về vấn đề này. Hoặc có lý do cụ thể không để làm điều đó? – mata
Có một lý do cụ thể (xin lỗi, ví dụ là một chút tầm thường). – Edwardr