On Feb 18, 2013, at 12:10 PM, Juraj Variny <[email protected]> wrote:

> Hello,
> 
> I should have expected refresh() to have problem with dirty objects, but if 
> it isn't a bug, maybe it should be at least documented.
> 
> To explain whole situation and why do I call the refresh() at all: I have 
> Account persistent class, with balance property. When doing processing, I'm 
> locking the row whenever it is necessary to update it (to not lock more rows 
> than necessary), like:
> 
> def update(acct,...):
>     DBSession.refresh(acct,lockmode='update')
> #update balance, add transaction record,return
> 
> The problem is, this function can be called multiple times in one session and 
> subsequent refresh calls throw out unsaved changes. So far I have fixed it by 
> placing DBSession.flush() calls. But calling flush() in the middle of 
> processing implies risk of problems with unmatched constraints (not fully 
> fleshed out data). Another idea is to mark already locked objects so that 
> refresh() is called only first time in a transaction. Such reentrant behavior 
> may be useful to have, what do you think?

if you just want to emit a SELECT .. FOR UPDATE you can just emit that 
directly.   If you specify with_lockmode() on query(), the get() will emit a 
SELECT unconditionally:

session.query(Account).with_lockmode('update').get(my_account.id)

it would be more efficient to not emit this SELECT more times than needed 
though this is easy enough to roll on top of a session, like a "lock_object()" 
function…can be tracked with events, here's also generalized:

from sqlalchemy import event
from sqlalchemy.orm import Session, object_session, object_mapper

@event.listens_for(Session, "after_begin")
def setup_lock_collection(session, *args):
    session._locked = set()

@event.listens_for(Session, "after_commit")
@event.listens_for(Session, "after_rollback")
def clear_lock_collection(session):
    session._locked.clear()

def lock_object(obj):
    session = object_session(obj)
    mapper = object_mapper(my_account)
    pk = mapper.primary_key_from_instance(my_account)
    if (mapper, pk) not in session._locked:
        session.query(mapper).with_lockmode('update').get(pk)
        session._locked.add((mapper, pk))




-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to