On Apr 15, 2009, at 8:13 PM, dykang wrote:

>
> The following code is a simple reproduction of the issue.
>
> # create your metadata and session
> import sqlalchemy
>
> table = sqlalchemy.Table (
>        'test_table', meta,
>        sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
>        sqlalchemy.Column('foo', sqlalchemy.Integer),
>        mysql_engine='InnoDB'
> )
>
> class Bar(object):
>        pass
>
> mapper =sqlalchemy.orm.mapper(Bar, table)
> meta.create_all()
>
>
> row1 = Bar()
> row1.foo = 1
> session.begin()
> session.save(row1)
> session.flush()
> s = table.update(table.c.foo == 1, values={table.c.foo: 2})
> session.connection(Bar).execute(s)
> session.commit()
>
> s = table.select(id == 1, for_update=True)
> row2 = session.query(Bar).from_statement(s).all()[0]
> print row2.foo


I cant reproduce that.  The session expires all data after commit().    
How are you creating your session ?

>
>    I am using sqlalchemy 0.4.7 and have tried it in 0.4.8 as well. I
> have not tried updating to 0.5.x yet, as I have some code that I'm not
> ready to migrate yet. Am I doing something wrong, or do I have a bad
> expectation? when using for_update, I do not expect to ever get stale
> data.

that explains that.  0.4 doesn't include expire-on-commit, so you  
should upgrade.  Otherwise, call session.expire_all() if you're stuck  
with 0.4 to see the results of your non-ORM UPDATE statements within  
your current session.  the usage of for_update has no effect on this  
behavior, it only determines if SQLA sends out a FOR UPDATE within the  
SELECT, thereby placing a read/write lock on the row.

>    In fact, since I am using transaction isolation level "read
> committed" even without the for_update, I would want to get the
> correct, updated value. Since the identity_map is NOT a cache, and the
> select statement is always executed, I would expect the updated values
> to always be returned.

the ORM is always going to use the values in the identity map within  
the session, and it is a cache in some ways.   Its a cache of data as  
it exists within the current transaction, since in the typical  
isolated transaction, there's no need to reload data until the  
transaction is complete.

In this sense, your usage of a non-isolated transaction mode (and the  
expectation of receiving rows that way) is somewhat incompatible with  
SQLAlchemy's notion of a unit of work.    However, there's a "reload  
fresh data every time" mode if you use the populate_existing() method  
on Query, which is provided for those few folks who want to work that  
way (not many folks want to work this way...I can't see what  
advantages there are to working non-isolated other than evading  
deadlocks).    you can add a method to Session which just returns a  
Query object with populate_existing() already set, if you like.

The reason you wouldn't want to use populate_existing every time is  
because it will blow away any changes pending on your attributes,  
which is why its never a default behavior.       but if you're trying  
to do a total read-only thing, it might fit the bill.


--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to