2012-04-18 40 views
12

Tôi gặp sự cố bộ nhớ cache khi tôi sử dụng sqlalchemy. Tôi sử dụng sqlalchemy chèn dữ liệu vào cơ sở dữ liệu mysql. Tôi có quá trình ứng dụng khác dữ liệu này sau đó cập nhật dữ liệu này trực tiếp. Nhưng sqlalchemy của tôi luôn có dữ liệu cũ hơn là dữ liệu cập nhật .. Tôi nghĩ rằng sqlalchemy đã lưu trong bộ nhớ cache yêu cầu của tôi .. vậy .. Làm thế nào để vô hiệu hóa nó?Làm thế nào để vô hiệu hóa bộ nhớ cache SQLAlchemy?

+1

Có liên quan? http://stackoverflow.com/questions/16586114/sqlalchemy-returns-stale-rows –

Trả lời

34

Nguyên nhân thông thường cho mọi người nghĩ rằng có một "bộ nhớ cache" lúc chơi, ngoài bản đồ nhận dạng SQLAlchemy thông thường là cục bộ cho giao dịch, là họ đang quan sát ảnh hưởng của việc cô lập giao dịch. SQLAlchemy của phiên làm việc theo mặc định trong một chế độ giao dịch, có nghĩa là nó chờ đợi cho đến khi session.commit() được gọi là để duy trì dữ liệu vào cơ sở dữ liệu. Trong thời gian này, các giao dịch khác đang diễn ra ở nơi khác sẽ không thấy dữ liệu này.

Tuy nhiên, do tính chất cô lập của các giao dịch, có thêm một twist. Các giao dịch khác đang diễn ra sẽ không chỉ không thấy dữ liệu giao dịch của bạn cho đến khi nó được cam kết, họ cũng không thể thấy nó trong một số trường hợp cho đến khi họ cam kết hoặc quay lại cũng (đó là hiệu ứng tương tự mà bạn đóng() đây). Một giao dịch có mức độ trung bình là cách ly sẽ giữ trạng thái đã tải cho đến thời điểm này và giữ cho bạn cùng một trạng thái cục bộ cho giao dịch ngay cả khi dữ liệu thực đã thay đổi - được gọi là lần đọc trong giao dịch này cách ly.

http://en.wikipedia.org/wiki/Isolation_%28database_systems%29

-1

Như tôi đã biết SQLAlchemy does not store caches, vì vậy bạn cần xem kết quả logging.

+0

Tôi nghĩ vậy. Tôi đã mở 'echo = True' nhưng không có gì hữu ích. –

+0

bạn có cập nhật phiên với cam kết không? –

+0

Tôi cập nhật dữ liệu mà không sử dụng sqlalchemy .. sử dụng 'MySQLdb' .. Tôi đảm bảo dữ liệu đã cập nhật trong MySQL .. –

0

Đầu tiên, không có bộ nhớ cache cho SQLAlchemy. Dựa trên phương pháp của bạn để tìm nạp dữ liệu từ DB, bạn nên thực hiện một số kiểm tra sau khi cơ sở dữ liệu được cập nhật bởi những người khác, xem liệu bạn có thể lấy dữ liệu mới hay không.

(1) use connection: 
connection = engine.connect() 
result = connection.execute("select username from users") 
for row in result: 
    print "username:", row['username'] 
connection.close() 
(2) use Engine ... 
(3) use MegaData... 

xin folowing bước trong: http://docs.sqlalchemy.org/en/latest/core/connections.html

Một lý do khác có thể là MySQL DB của bạn không được cập nhật thường xuyên. Khởi động lại dịch vụ MySQL và có một kiểm tra.

+0

Cảm ơn bạn đã trả lời. Tôi đã giải quyết nó. Tôi chỉ quên 'session.close' khi tôi sử dụng' scoped_session' ... –

3

Ngoài ra để zzzeek câu trả lời xuất sắc,

Tôi đã có một vấn đề tương tự. Tôi giải quyết vấn đề bằng cách sử dụng các phiên họp ngắn.

with closing(new_session()) as sess: 
    # do your stuff 

Tôi đã sử dụng phiên mới cho mỗi tác vụ, nhóm tác vụ hoặc yêu cầu (trong trường hợp ứng dụng web). Điều đó giải quyết vấn đề "bộ nhớ đệm" cho tôi.

Tài liệu này đã rất hữu ích cho tôi:

When do I construct a Session, when do I commit it, and when do I close it

+1

Liên kết ở trên sẽ chuyển sang tài liệu cho phiên. Tiêu đề ngụ ý nó nên được chỉ ở đây: http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#session-faq-whentocreate – mozey

11

Vấn đề này đã được thực sự bực bội đối với tôi, nhưng cuối cùng tôi đã tìm nó ra.

Tôi có một ứng dụng Flask/SQLAlchemy chạy cùng với một trang web PHP cũ hơn. Trang PHP sẽ ghi vào cơ sở dữ liệu và SQLAlchemy sẽ không nhận thức được bất kỳ thay đổi nào.

Tôi đã thử cài đặt phiên làm việc autoflush = True không thành công Tôi đã thử db_session.flush(), db_session.expire_all() và db_session.commit() trước khi truy vấn và KHÔNG làm việc. Vẫn hiển thị dữ liệu cũ.

Cuối cùng tôi đi qua phần này của tài liệu SQLAlchemy: http://docs.sqlalchemy.org/en/latest/dialects/postgresql.html#transaction-isolation-level

Thiết lập isolation_level làm việc tuyệt vời. Bây giờ ứng dụng Flask của tôi là "nói chuyện" với ứng dụng PHP. Dưới đây là các mã:

engine = create_engine(
       "postgresql+pg8000://scott:[email protected]/test", 
       isolation_level="READ UNCOMMITTED" 
      ) 

Khi động cơ SQLAlchemy được bắt đầu với "ĐỌC uncommited" isolation_level nó sẽ thực hiện "bẩn lần đọc" có nghĩa là nó sẽ đọc thay đổi uncommited trực tiếp từ cơ sở dữ liệu.

Hope this helps


Dưới đây là một giải pháp lịch sự có thể có của AaronD trong các ý kiến ​​

from flask.ext.sqlalchemy import SQLAlchemy 

class UnlockedAlchemy(SQLAlchemy): 
    def apply_driver_hacks(self, app, info, options): 
     if "isolation_level" not in options: 
      options["isolation_level"] = "READ COMMITTED" 
    return super(UnlockedAlchemy, self).apply_driver_hacks(app, info, options) 
+0

Nếu bạn đang sử dụng Flask-SQLAlchemy, bạn có thể phân lớp 'flask.ext .sqlalchemy.SQLAlchemy' và ghi đè hàm 'apply_driver_hacks' để thiết lập mức cô lập, trong khi vẫn giữ tất cả các tích hợp Flask. Ngoài ra, có lẽ mức cô lập 'READ COMMITTED' là đủ cung cấp cho cả hai ứng dụng cam kết viết của chúng sau khi chúng tạo ra chúng và không chờ đợi trong một thời gian dài. Bằng cách đó bạn không phải lo lắng về những lần đọc bẩn - nó chỉ cung cấp cho bạn một ảnh chụp nhanh DB mới mỗi khi bạn đọc. –

+0

@AaronD Bạn có thể đăng mã của bạn lên phân lớp 'flask.ext.sqlalchemy.SQLAlchemy' như bạn đã đề cập không? –

+1

Tôi chỉ có điều này trong mã của tôi: lớp 'UnlockedAlchemy (SQLAlchemy): def apply_driver_hacks (tự, ứng dụng, thông tin, tùy chọn): nếu không phải là "isolation_level" trong tùy chọn: tùy chọn [ "isolation_level"] = "ĐỌC CAM KẾT " return super (UnlockedAlchemy, self) .apply_driver_hacks (ứng dụng, thông tin, tùy chọn)' –

3

này đã xảy ra trong ứng dụng Flask của tôi, và giải pháp của tôi đã hết hạn tất cả các đối tượng trong phiên sau mỗi yêu cầu.

from flask.signals import request_finished 
def expire_session(sender, response, **extra): 
    app.db.session.expire_all() 
request_finished.connect(expire_session, flask_app) 

Làm việc như một sự quyến rũ.

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