On Jan 9, 2014, at 7:17 PM, Weikai Xie <xiewei...@gmail.com> wrote: > Hi, folks, > > I observed that it seems all ORM objects in a session will expire > immediately if there is a failure in session.flush(). I was wondering what's > the rationale behind this behavior. > > Following is an artificial web application code to illustrate the idea: > > def PUT(): > .... > # session and engine are all created with default parameter > > user = session.query(UserProfile).first() > > # deliberately tries to insert a Login record which has the same > primary key as an existing one such that the later session.flush() will fail > try: > duplicated_login_record = Login(id=0, username="username:weikai") > session.add(duplicated_login_record) > session.flush() > except IntegrityError: > session.rollback() > > print user.id > ... > > By turning on logging, I noticed the "print user.id" line always result in a > new SELECT being issued to database, which is an indicator that somehow user > object got expired after the failure in session.flush(). > > For some other good reason which I don't want to elaborate here, we really > don't want to have an extra SELECT going to DB in the processing of one HTTP > request. Therefore, I was just wondering why is this behavior and whether it > can be turned off.
The short answer is that this behavior can’t be disabled across the board, unless you are using SAVEPOINTs, which you probably should here. The flush() process does a rollback() immediately on the inner transaction when an exception occurs, and once the transaction is rolled back all data is expired; as the objects are proxies for the state of the database, and the transaction has been rolled back, the state of the objects is invalid. I do notice that you’re catching an IntegrityError. The typical pattern when writing code that wants to catch these and then continue is to run the individual set of questionable operations within a SAVEPOINT, that is a begin_nested()/commit() block. Recent versions of SQLAlchemy have the behavior such that when a flush() exception rolls back the SAVEPOINT, objects that were not modified within the SAVEPOINT are not expired; only those objects that changed within the save point’s scope do. There’s also an option called _enable_transaction_accounting which if set to False will disable *all* rollback/commit accounting, basically reverts to pre-0.5 behavior. Using this flag, you’re giving up a lot of the Session’s functionality and as this mode is not really supported I’m not sure what other useful features you might be giving up. > > > > > > > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/groups/opt_out.
signature.asc
Description: Message signed with OpenPGP using GPGMail