On Mon, Nov 22, 2010 at 6:03 AM, Shai Berger <s...@platonix.com> wrote: > Hi list, > > #9964 is about managed transactions not being committed under transaction > middleware (or transaction.commit_on_success decorator) after the database was > modified via raw SQL. The root cause of that is that, today, managed > transactions only become "dirty" when there is clear evidence of database > change -- that is, when a known-to-change-the-database operation (such as > saving a model) is performed. If this isn't the case (as in the case of raw > SQL), the user is required to call transaction.set_dirty() to get correct > behavior. > > More generally, transactions which stay "clean" are not really closed by the > transaction-management mechanism. If the transaction is part of a request, it > will be implicitly rolled back at the end of the request when the connection > is closed. If, under any circumstances, the connection stays open, so does the > transaction; this is rare, but wrong, and a user will have no warning except > for bugs creeping up. > > Yesterday I submitted a patch for this bug, which corrects this behavior by > stipulating that every transaction where an operation was performed in managed > mode should be considered dirty. In other words, there are no more "read-only > transactions". Every (managed) transaction that is opened must be closed. > > This is a backward-incompatible change: most users, who either use automatic > mode or some form of commit_on_success, should see no difference, but users > working with commit_manually will be forced to close read-only transactions > explicitly -- which they could get away with not doing before. > > I believe this leads to more correct code even in these cases, and all in all, > it trades a silent gotcha in one situation for a clear exception in another: > Under the current scheme, raw SQL execution can get rolled back silently if > set_dirty() isn't called; while this is documented, it is a gotcha. Under my > proposed fix, unclosed read-only transactions raise a > TransactionManagementError. I think this is an overall improvement. > > But I also think more people would have an opinion about it, than those who > follow http://code.djangoproject.com/ticket/9964.
Hi Shai, First off - thanks for the effort you've put into this issue, and the gentle persistence with which you've pursued it. The proposal you've got on the table is a lot closer to being trunk-ready than it has been historically. It's a lot simpler, and makes a lot more sense. However, I have two comments on the patch you've proposed. 1) Why introduce a full class wrapper with a customizable on_use() handler when there is only one meaningful course of action -- if managed, set dirty. Why not just embed that logic direct into Django's cursor (which is itself a wrapper anyway)? 2) The introduction of a backwards incompatibility doesn't fill me with joy. Code that works today must work tomorrow, however inconvenient it is to accommodate. The fact that Django's own test suite needs modifications in order to pass sends up a warning flag for me -- if our test suite needs modifications in non-obvious places (i.e., places that aren't directly related to testing transactions), then so will end-user code. However, that doesn't mean we're completely prevented from making change. We could make this change under two circumstances. Either: a) We need to find a way to gracefully introduce this change, raising a PendingDeprecationWarning in 1.3, a DeprecationWarning in 1.4, and finally making the change in 1.5; but if the user opts-in, the warning will be silenced. A setting isn't the right way to handle this, because settings apply across an entire project, but different reusable apps may be in different states of compliance. b) We need to declare that the current behavior to be a bug. We can break backwards compatibility to correct behavior that is clearly wrong. I haven't fully thought through the consequences here, but I think the combination of the footprint of affected cases, combined with the side effects of having dangling connections and transactions might almost be enough to convince me that can invoke the bug clause to break backwards compatibility. If you (or anyone else) has any opinions on this, I'd be interested in hearing them. To be clear -- as I understand it, we're talking about any code that: * is in a transaction managed block (i.e., between manually invoked enter/leave_transaction_management() calls, or within the scope of a commit_manually decorator/context manager), and * has a select or other manual cursor activity *after* the last commit/rollback, but *before* the end of the transaction management block, when there hasn't been a model save or other 'dirtying' behavior invoked after the last commit/rollback At present, such code is allowed to pass, and the transaction dangles. The proposed change would declare this situation a bug, requiring a manual commit/rollback at the end of any database activity. Yours, Russ Magee %-) -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-develop...@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.