2010-11-17 52 views
273

Sự khác nhau giữa flush()commit() trong SQLAlchemy là gì?SQLAlchemy: Sự khác biệt giữa flush() và commit() là gì?

Tôi đã đọc tài liệu, nhưng không ai khôn ngoan hơn - dường như họ cho rằng tôi không có hiểu biết trước.

Tôi đặc biệt quan tâm đến tác động của chúng đến việc sử dụng bộ nhớ. Tôi đang tải một số dữ liệu vào một cơ sở dữ liệu từ một loạt các tập tin (khoảng 5 triệu hàng trong tổng số) và phiên của tôi đôi khi rơi xuống - đó là một cơ sở dữ liệu lớn và một máy không có nhiều bộ nhớ.

Tôi tự hỏi nếu tôi đang sử dụng quá nhiều commit() và không đủ flush() cuộc gọi - nhưng không thực sự hiểu sự khác biệt là gì, thật khó để nói!

Trả lời

334

Đối tượng phiên là cơ bản một giao dịch liên tục về các thay đổi đối với cơ sở dữ liệu (cập nhật, chèn, xóa). Các hoạt động này không được lưu giữ lâu dài cho cơ sở dữ liệu cho đến khi chúng được cam kết (nếu chương trình của bạn hủy bỏ một số lý do trong giao dịch giữa phiên, bất kỳ thay đổi không cam kết nào bị mất).

Đối tượng phiên đăng ký hoạt động giao dịch với session.add(), nhưng chưa truyền đạt chúng đến cơ sở dữ liệu cho đến khi session.flush() được gọi.

session.flush() liên lạc một loạt các thao tác với cơ sở dữ liệu (chèn, cập nhật, xóa). Cơ sở dữ liệu duy trì chúng như các hoạt động đang chờ xử lý trong một giao dịch. Các thay đổi không được lưu giữ vĩnh viễn vào đĩa hoặc hiển thị với các giao dịch khác cho đến khi cơ sở dữ liệu nhận được một COMMIT cho giao dịch hiện tại (đó là những gì session.commit() thực hiện).

session.commit() cam kết (vẫn còn) những thay đổi đó đối với cơ sở dữ liệu.

flush()luôn gọi được gọi là một phần của cuộc gọi đến commit() (1).

Khi bạn sử dụng đối tượng Phiên để truy vấn cơ sở dữ liệu, truy vấn sẽ trả về kết quả cả từ cơ sở dữ liệu và từ các phần bị xóa của giao dịch không cam kết mà nó nắm giữ. Theo mặc định, đối tượng Session autoflush hoạt động của chúng, nhưng điều này có thể bị vô hiệu hóa.

Hy vọng rằng ví dụ này sẽ làm cho rõ ràng hơn này:

#--- 
s = Session() 

s.add(Foo('A')) # The Foo('A') object has been added to the session. 
       # It has not been committed to the database yet, 
       # but is returned as part of a query. 
print 1, s.query(Foo).all() 
s.commit() 

#--- 
s2 = Session() 
s2.autoflush = False 

s2.add(Foo('B')) 
print 2, s2.query(Foo).all() # The Foo('B') object is *not* returned 
          # as part of this query because it hasn't 
          # been flushed yet. 
s2.flush()     # Now, Foo('B') is in the same state as 
          # Foo('A') was above. 
print 3, s2.query(Foo).all() 
s2.rollback()    # Foo('B') has not been committed, and rolling 
          # back the session's transaction removes it 
          # from the session. 
print 4, s2.query(Foo).all() 

#--- 
Output: 
1 [<Foo('A')>] 
2 [<Foo('A')>] 
3 [<Foo('A')>, <Foo('B')>] 
4 [<Foo('A')>] 
+0

Chỉ cần một điều nữa: bạn có biết liệu gọi cam kết() tăng bộ nhớ được sử dụng hay giảm không? – AP257

+2

Điều này cũng sai cho các công cụ db không hỗ trợ các giao dịch như myisam. Vì không có giao dịch đang diễn ra, việc tuôn ra thậm chí còn ít hơn để phân biệt với cam kết. – underrun

+0

@underrun Vì vậy, nếu tôi làm 'session.query()' sau 'session.flush()', tôi có thấy các thay đổi của mình không? Vì tôi đang sử dụng MyISAM. –

9

Như @snapshoe nói

flush() gửi câu lệnh SQL của bạn vào cơ sở dữ liệu

commit() cam kết giao dịch.

Khi session.autocommit == False:

cam kết() sẽ gọi flush() nếu autoflush bạn == True.

Khi phiên.autocommit == True:

Bạn không thể gọi cam kết() nếu bạn chưa bắt đầu giao dịch (có thể bạn chưa sử dụng chế độ này để tránh quản lý giao dịch theo cách thủ công).

Trong chế độ này, bạn phải gọi flush() để lưu thay đổi ORM của bạn. Việc xả hiệu quả cũng cam kết dữ liệu của bạn.

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