Hi, thanks for your reply.



On 11/13/2011 05:15 PM, Michael Bayer wrote:
 From what I've read in the docs, I am supposed to do session.refresh(),
No that's not required at all.  All the objects that are still referenced 
outside the session, stay present in the session and will reload their data 
when accessed.


But they're not, I'm getting Instance XY is not present in this Session, for readonly_model when method_two is called, if there was a rollback in method_one.

Now, what I forgot to say is that I'm doing this within a Pyramid application which uses ZODB Transactions, so I can't directly access session.commit() .rollback() or .savepoint(). I am not quite sure what else does Transaction do when it encounters a failed state, I've already asked on the Pyramid mailing list about having multiple transactions within the same request, waiting to resolve that issue.





What you will lose is whatever pending changes were present in method one, 
whatever data was flushed but not committed.

But when you say method one "proceeds within a new transaction" - doesn't that 
imply that it re-tried its full series of steps, so that the required state is apparent 
at the end of method one ?    if method one is where the data is being set up for method 
two, it of course would have to re-establish that state for which method two is dependent.

The issue is basically this. At the end of a HTTP request, after all "main" data has been read, changed and flushed to db, I have to make certain statistical entries for several relations. Now, these statistical entries have current date as one part of the primary key, meaning each row is one DAY.

So the stats recording method (two calls beacuse there are two statistical models/tables) tries to insert date as new row, and if it fails (has already been set by another process) with IntegrityError, then it tries to update existing rows. I can't merge, because between merge's select and decision whether to insert or update another process may have created the entry, so I would STILL have the IntegrityError and have to retry the steps.

I know that his may not be a best approach, perhaps I should just have insert only statistical entries and then aggregate everything into daily pivot tables, but nevertheless I wish to understand and learn how to properly deal with rollbacks and retrying transactions.


Anyways, even if I catch IntegrityError, the transaction fails with "TransactionFailedError: An operation previously failed, with traceback". Meanwhile (since posting this original question) I've learned that the error belongs to Zope and not SQLAlchemy per se, and this whole problem may be because of that.

I've also tried with savepoints so that the integrity error above would rollback only THAT attempt, but I still encounter the TransactionFailedError...

So I'm guessing that the method one and two can simply use savepoints and isolate their own failures from the "outside" transaction? That way I preserve logical isolation of the code, keeping in mind only that all data will be flushed with savepoint. Which then makes this problem coming from the Pyramid framework implementation with ZODB transaction.



One way would be to extract data from the readonly_model:

readonly_data = readonly_model.readonly_data

method_one(readonly_data, param_1, param_2, ...)
is the issue here attempting to avoid redundant SELECT of the data ?   
readonly_model.readonly_data will otherwise refresh itself when you access it.

No, only to avoid Instance not present in Session error that appears if method_one failed and I'm trying to use readonly_model again.


if it were me, I'd never be even trying to "redo" an operation that rolled 
back.    99% of the time if my app has to rollback a transaction in the middle of an 
operation, that's a bug in the application no different from a crash.

But with IntegrityErrors there is no other way? Relying on this error keeps the atomicity within the MVCC of the database (PostgreSQL in my case) and not in the application (via merge, or select for update -- which btw can't be done for inserts).



If I absolutely needed to use the pattern of "try to insert a record with a key, it 
might fail because it's unique", I'd use Session.begin_nested() so that the method 
in question in effect uses SAVEPOINT, gets its own transactional state that doesn't 
affect things outside of it.

Yes, see my comments above about savepoints.


--
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to