2010-08-19 30 views
7

Chúng tôi đang sử dụng cơ sở khai báo SQLAlchemy và tôi có một phương thức mà tôi muốn tách biệt mức giao dịch cho. Để giải thích, có hai quá trình đồng thời ghi vào cơ sở dữ liệu và tôi phải yêu cầu chúng thực thi logic của chúng trong một giao dịch. Mức cô lập giao dịch mặc định là READ COMMITTED, nhưng tôi cần có khả năng thực hiện một đoạn mã bằng cách sử dụng các mức cô lập SERIALIZABLE.Làm cách nào để đặt mức cô lập giao dịch trong SQLAlchemy cho PostgreSQL?

Điều này được thực hiện bằng SQLAlchemy như thế nào? Ngay bây giờ, về cơ bản tôi có một phương thức trong mô hình của chúng ta, được thừa hưởng từ cơ sở khai báo của SQLAlchemy, về cơ bản cần được giao dịch được gọi ra.

from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT 
from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED 
from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE 

class OurClass(SQLAlchemyBaseModel): 

    @classmethod 
    def set_isolation_level(cls, level=ISOLATION_LEVEL_SERIALIZABLE): 
     cls.get_engine().connect().connection.set_isolation_level(level) 

    @classmethod 
    def find_or_create(cls, **kwargs): 
     try: 
      return cls.query().filter_by(**kwargs).one() 
     except NoResultFound: 
      x = cls(**kwargs) 
      x.save() 
      return x 

Tôi đang thực hiện điều này để gọi điều này bằng cách sử dụng mức cô lập giao dịch, nhưng nó không làm những gì tôi mong đợi. Mức cô lập vẫn là READ COMMITTED từ những gì tôi thấy trong nhật ký postgres. Ai đó có thể giúp xác định những gì tôi đang làm gì sai?

Tôi đang sử dụng SQLAlchemy 0.5.5

class Foo(OurClass): 

    def insert_this(self, kwarg1=value1): 
     # I am trying to set the isolation level to SERIALIZABLE 
     try: 
      self.set_isolation_level() 
      with Session.begin(): 
       self.find_or_create(kwarg1=value1) 
     except Exception: # if any exception is thrown... 
      print "I caught an expection." 
      print sys.exc_info() 
     finally: 
      # Make the isolation level back to READ COMMITTED 
      self.set_isolation_level(ISOLATION_LEVEL_READ_COMMITTED) 

Trả lời

7

Từ Michael Bayer, nhà duy trì SQLAlchemy:

Vui lòng sử dụng các "isolation_level" lập luận để create_engine() và sử dụng latest tip of SQLAlchemy cho đến 0.6.4 được phát hành, như đã có một psycopg2 lỗi cụ thể được sửa gần đây liên quan đến mức cách ly.

Cách tiếp cận bạn có dưới đây không ảnh hưởng đến cùng một kết nối đó là sau sử dụng để truy vấn - bạn muốn thay vì sử dụng một PoolListener mà bộ lên set_isolation_level trên tất cả các kết nối khi chúng được tạo ra.

+3

Dường như đối số 'isolation_level' thành' create_engine() 'chỉ ảnh hưởng đến trình quản lý kết nối chính để bạn có được mức cô lập đó trên mỗi kết nối. Bạn có tìm ra cách tương thích kết nối tổng hợp để đạt được điều này trên cơ sở mỗi phiên/kết nối không? Câu hỏi ban đầu của bạn có vẻ như bạn chỉ muốn nó trên một phương pháp nhất định. – Russ

-3

Mức cô lập được thiết lập trong một giao dịch, ví dụ

try: 
    Session.begin() 
    Session.execute('set transaction isolation level serializable') 
    self.find_or_create(kwarg1=value1) 
except: 
    ... 

Từ PostgreSQL doc:

Nếu SET GIAO DỊCH được thực hiện mà không có một GIAO DỊCH BẮT ĐẦU trước hoặc BEGIN, nó sẽ xuất hiện để không có hiệu lực, kể từ khi giao dịch sẽ kết thúc ngay lập tức.

+0

Tôi sẽ kiểm tra câu trả lời của bạn vào ngày mai và chấp nhận câu trả lời này nếu nó hoạt động :) Tôi có cảm giác như vậy. –

+0

Câu trả lời của bạn không hoạt động. Theo Michael Bayer, có vẻ như mức độ cô lập giao dịch không ảnh hưởng đến cùng một kết nối mà sau này được sử dụng để truy vấn. –

+0

Tôi tin rằng bình luận của Michael Bayer là về mã của bạn chứ không phải của tôi. Sự khác biệt là bạn đặt mức cách ly trước khi bắt đầu giao dịch. Bạn đã thực sự thử mã trước khi tuyên bố nó không hoạt động? – sayap

Các vấn đề liên quan