1. Michael Bayer
  2. sqlalchemy
  3. Issues

Issues

Issue #113 resolved

out-of-transaction Sessions

Michael Bayer
repo owner created an issue

Session gets a flag "external_connection" or something like that which means it will interrupt the engine's current connection with a new one from the pool, and use that for committing, also replacing it as the "current connection" upon push()/pop() so that select statements within mapper use this new connection as well, if they call mapper.using(sess).

basically, need to be able to say s = Session(), where s will not participate with the current thread's connection, transactionalized or not. so engine needs to support this pattern at an abstracted level (i.e., so that all selects/execs etc. can partcipate). this is def. a hibernate thing which has everything more localized to an explicit session....

this will need something on engine like start_nested()/end_nested() that interrupts the transaction going on, if any, or the current thread local connection...connection pool should now have use_threadlocal turned off, SingletonPool will have to be improved to support real pooled behavior, the current thread management will be handled by the engine. Session will have to use these with a push/pop, also within a commit(), and somehow have those two use the same nested() if they are used together

general idea is:

s = Session(external_connection=True)
x = MyObj(_sa_session = s)
y = MyObj()
engine.begin()
y.etc

s.commit() # commits s, readable in the DB now
objectstore.commit()

engine.rollback()

this is important stuff since engine conflates the concepts of "database identity" with "connection/session", sorta like how mapper conflates "class structutre" with "query generation"...the concept of Sessions, ORM or no, needs to be nailed down better.

Comments (1)

  1. Michael Bayer reporter

    this has been implemented , final commit is changeset:1181.

    unit test looks like this:

            class User(object):
                pass
            testbase.db.begin()
            try:
                m = mapper(User, users)
                name1 = "Oliver Twist"
                name2 = 'Mr. Bumble'
                m.get(7).user_name = name1
                s = objectstore.Session(nest_on=testbase.db)
                m.using(s).get(8).user_name = name2
                s.commit()
                objectstore.commit()
                testbase.db.rollback()
            except:
                testbase.db.rollback()
                raise
            objectstore.clear()
            self.assert_(m.get(8).user_name == name2)
            self.assert_(m.get(7).user_name != name1)
    

    the Session needs an explicit list of what Engines to "nest" with, since Session works across multi-engines and it would be very difficult for it to figure out what engines need the nested transaction outside of a commit(). Id prefer it to just be "True", but this is still pretty sparse. also works with plain objectstore.push_session()/pop_session(). Also, can be done via engine completely, i.e. engine.push_session()/pop_session().

    issue now is, two levels of "begin/commit/session" with slightly different meanings. might have to do a name change at some level, or document creatively.

  2. Log in to comment