Trích dẫn "Làm cách nào để sử dụng engine / kết nối / phiên với đa xử lý Python hoặc os.fork ()?" với sự nhấn mạnh thêm:
Đối tượng SQLAlchemy Engine đề cập đến một nhóm kết nối của các kết nối cơ sở dữ liệu hiện có. Vì vậy, khi đối tượng này được sao chép sang quy trình con, mục tiêu là đảm bảo rằng không có kết nối cơ sở dữ liệu nào được chuyển sang .
và
Tuy nhiên, đối với trường hợp Phiên hoặc Kết nối đang hoạt động giao dịch được chia sẻ, không có bản sửa lỗi tự động nào cho việc này; ứng dụng cần đảm bảo một quy trình con mới chỉ khởi tạo các đối tượng và giao dịch Kết nối mới, cũng như các đối tượng Phiên ORM.
Sự cố bắt nguồn từ quá trình con được chia nhỏ kế thừa session
toàn cầu trực tiếp , đang giữ một Connection
. Khi target
cuộc gọi init
, nó ghi đè các tham chiếu chung đến engine
và session
, do đó giảm số tiền hoàn lại của chúng xuống 0 ở trẻ, buộc chúng phải hoàn tất. Ví dụ:nếu bạn bằng cách này hay cách khác tạo một tham chiếu khác đến phiên kế thừa trong phần con, bạn sẽ ngăn nó bị xóa - nhưng đừng làm điều đó. Sau main
đã tham gia và trở lại hoạt động kinh doanh như bình thường. Nó đang cố gắng sử dụng kết nối hiện có khả năng đã hoàn thiện - hoặc không đồng bộ - kết nối. Về lý do tại sao điều này gây ra lỗi chỉ sau một số lần lặp lại, tôi không chắc.
Cách duy nhất để xử lý tình huống này bằng cách sử dụng hình cầu theo cách bạn làm là
- Đóng tất cả các phiên
- Gọi
engine.dispose()
trước khi rèn. Điều này sẽ ngăn không cho các kết nối bị rò rỉ sang đứa trẻ. Ví dụ:
def main():
global session
init()
try:
dummy = Dummy(value=1)
session.add(dummy)
session.commit()
dummy_id = dummy.id
# Return the Connection to the pool
session.close()
# Dispose of it!
engine.dispose()
# ...or call your cleanup() function, which does the same
p = multiprocessing.Process(target=target, args=(dummy_id,))
p.start()
p.join()
# Start a new session
session = Session()
dummy = session.query(Dummy).get(dummy_id)
assert dummy.value == 2
finally:
cleanup()
Ví dụ thứ hai của bạn không kích hoạt quá trình hoàn thiện trong phần con và vì vậy nó chỉ có vẻ hoạt động, mặc dù nó có thể bị hỏng như ví dụ đầu tiên, vì nó vẫn đang kế thừa một bản sao của phiên và kết nối của nó được xác định cục bộ trong main
.