On Dec 19, 2012, at 4:29 AM, charlax wrote: > > So the problem here is that the rollback does nothing, because there's a > commit in the delete_password method (in this example there's only method > called, in reality I have multiple methods). I think having stuff being > committed in a model's method is antipattern (is it?)
I think it is. I wish I could find more authoritative sources for this but in my opinion, as well as all the experience I've had with transaction-aware frameworks, transaction demarcation is specified in the application in exactly one place, in a position that surrounds all the business logic. The business logic itself should not have any awareness of transaction demarcation. I've updated the docs significantly to talk about this pattern here: http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#session-frequently-asked-questions, in the question "when do I construct a Session?". Web frameworks present the simplest pattern, but if your application is not a web application, you'd want to decide on where your app's concept of "business methods" can be enclosed. > but I'd like to know if there's a simple way to get the desired behavior. I > tried: > Manually setting a savepoint (Session.execute("SAVEPOINT soft_delete")). But > commit in delete_password closes the connection so the savepoint is lost. > Using begin_nested and begin(subtransactions=True), but commit in > delete_password closes the context > I thought of using autocommit=True but it seems it's not recommended (and I'm > not sure to understand all the implications of this), or creating an external > transaction but the example in the doc is only for tests so I'm not sure if > it's antipattern too. Also, getting access to the engine would require quite > a small refactor of my app. the subtransaction thing could allow this, if your ad-hoc commit() method also called begin(subtransactions=True) before it did its work, but this implies the Session is being used in autocommit mode. But there's no reason to use autocommit, while it used to be the default system of use years ago, now it's only there for certain framework integrations that want to be able to emit begin() ahead of time. The Session otherwise shouldn't be used to emit SQL without a transaction present. Which means, there's really no reason in the world you need to call commit() inside that method, *unless* you're trying to expose that particular bit of data to the outside world before the enclosing transaction is complete - and for that use case I'd use a different transaction altogether. Otherwise, you're already in a transaction that isn't yet committed, which your app structure should ensure happens before the larger series of business methods is complete. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
