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.