On Thu, Jan 17, 2013 at 4:26 PM, Michael Bayer <mike...@zzzcomputing.com>wrote:

>
> On Jan 17, 2013, at 7:24 PM, Ken Lareau wrote:
>
>
>
> On Thu, Jan 17, 2013 at 4:13 PM, Michael Bayer 
> <mike...@zzzcomputing.com>wrote:
>
>>
>> On Jan 17, 2013, at 7:01 PM, Ken Lareau wrote:
>>
>> On Thu, Jan 17, 2013 at 3:54 PM, Michael Bayer 
>> <mike...@zzzcomputing.com>wrote:
>>
>>>
>>> On Jan 17, 2013, at 6:45 PM, Ken Lareau wrote:
>>>
>>> Sadly, it looks like when I try the code in my full application, it is
>>> failing miserably.
>>> I'm seeing errors like this:
>>>
>>> sqlalchemy.orm.exc.DetachedInstanceError: Instance <Deployments at
>>> 0x3367910> is not bound to a Session; attribute refresh operation cannot
>>> proceed
>>>
>>> and
>>>
>>> sqlalchemy.exc.InvalidRequestError: Object '<HostDeployments at
>>> 0x21cd050>' is already attached to session '1' (this is '3')
>>>
>>> Sadly it's not immediately obvious as to what's going on... not even
>>> certain how
>>> to start debugging this problem.
>>>
>>>
>>> well an object can only be "attached" to one Session at a time.   so the
>>> tricky thing is that it's kind of easy to get objects in the Session
>>> sometimes when you don't want them to.  like if you have A and B, and
>>> there's a relationship between both like A.bs an B.a, putting an "A" into a
>>> Session will pull in the "B" and vice versa.
>>>
>>> So if you're putting some kind of object into this other Session to be
>>> committed immediately, you'd have to make sure it isn't being pulled into
>>> your primary session.   if you call object_session(someobj) on any object
>>> it will show you what Session it belongs to.
>>>
>>> The other option is to merge() the state of the object into another
>>> Session.  merge() makes a copy of an object from one Session to another.
>>>  Though here you're looking to commit those objects in the second session
>>> and not at all in the first so you probably should jsut make sure those
>>> objects are only in that one Session.
>>>
>>
>> That would explain things, since I have things like:
>>
>>      with isolated_transaction():
>>         host_dep.status = 'ok'
>>         Session.commit()
>>
>> Obviously the 'host_dep' is from the original session, so this isn't
>> going to work.  I know about merge(),
>> though in this case I'm not fully certain how to use it, or if it can
>> even solve issues like this. :(
>>
>>
>> OK you could merge in a situation like that:
>>
>> with isolated_transaction():
>>     merge_host_dep = Session.merge(host_dep)
>>     merge_host_dep.status = "ok"
>>     Session.commit()
>>
>> but now your "host_dep" is in a different state as "merge_host_dep", and
>> that row has a different value in the "isolated" transaction than the one
>> locally.  if you updated it locally, then you'd see that same UPDATE
>> statement happen again and it might even hit upon a conflict when you try
>> to commit the main transaction.
>>
>> the "using two transactions" pattern is sort of best if you can isolate
>> rows that are intended for one side or the other.
>>
>
> Sadly in this case... I can't isolate, at least not very easily.  The code
> is involved enough
> that extracting the necessary parts to isolate a given object for change
> would be very,
> very difficult, if not impossible.  Unfortunately this may require me to
> completely rewrite
> large parts of my application. :(
>
> I do thank you for all the help you've given so far, though.  It's been
> very much appre-
> ciated.
>
>
>
> since you're refactoring, perhaps there's a way to break out the things
> that need to be visible into new rows of their own ?
>

With the current base design, that may not be possible.  I could get into
the gory details
about what the application is doing and how it's interacting with the
database, but I fear
it may be more than the rest of the people on the mailing list would like
to hear.


- Ken

>
> - Ken
>
>
>> - Ken
>>
>>
>>>
>>>
>>>
>>> - Ken
>>>
>>>
>>> On Tue, Jan 8, 2013 at 2:59 PM, Ken Lareau <klar...@tagged.com> wrote:
>>>
>>>> On Tue, Jan 8, 2013 at 2:16 PM, Michael Bayer <mike...@zzzcomputing.com
>>>> > wrote:
>>>>
>>>>>
>>>>> On Jan 8, 2013, at 4:00 PM, Ken Lareau wrote:
>>>>>
>>>>>
>>>>> Given this and your previous comments, and after some conversations
>>>>> with
>>>>> a coworker, I decided to expose the 'engine' variable from the database
>>>>> library and create a context manager as so:
>>>>>
>>>>> @contextlib.contextmanager
>>>>> def isolated_transaction(NewSession=None):
>>>>>     """Manage a new transaction (session) within an existing session"""
>>>>>
>>>>>     needed_session = True
>>>>>     existing = Session.registry()
>>>>>
>>>>>     if NewSession is None:
>>>>>         NewSession = scoped_session(sessionmaker(bind=engine))
>>>>>     else:
>>>>>         needed_session = False
>>>>>
>>>>>     Session.registry.set(NewSession)
>>>>>
>>>>>     try:
>>>>>         yield
>>>>>     finally:
>>>>>         Session.registry.set(existing)
>>>>>
>>>>>         if needed_session:
>>>>>             NewSession.close()
>>>>>
>>>>>
>>>>> (This code hasn't quite been tested yet and may need some tweaking)
>>>>> With this, whenever I need an 'isolated' transaction I can simply do
>>>>> from my program:
>>>>>
>>>>>     with isolated_transaction():
>>>>>         <do stuff with Session>
>>>>>
>>>>> And things should 'just work'... at least that's my hope!  I can also
>>>>> pass
>>>>> an existing new session if I want to use one in multiple places (not
>>>>> sure I'll need that just yet, but it was easy enough to write into the
>>>>> method, so...)
>>>>>
>>>>> Hopefully this seems like a sane solution to my problem. :)
>>>>>
>>>>>
>>>>> its good, though you can save yourself all the trouble with
>>>>> scoped_session/sessionmaker by just saying this:
>>>>>
>>>>> from sqlalchemy.orm import Session
>>>>>  new_session = Session(bind=engine)
>>>>>
>>>>> or which might be even more portable, use the sessionmaker from your
>>>>> existing registry:
>>>>>
>>>>> new_session = Session.session_factory()
>>>>>
>>>>> session_factory is the sessionmaker() you stuck onto scoped_session in
>>>>> the first place.  In that case you don't need to refer to the Engine
>>>>> explicitly.
>>>>>
>>>>
>>>> Nice, the second one definitely works and I no longer need to export
>>>> 'engine'
>>>> and only need to import Session from my library where I have the context
>>>> manager place. :)
>>>>
>>>> Thanks again!
>>>>
>>>> - Ken
>>>>
>>>>
>>>>>>> Depending on the database in use, using low isolation levels can
>>>>>>> have the effect that other transactions can view "dirty reads" as the
>>>>>>> transaction proceeds, but this is obviously an all-or-nothing thing.
>>>>>>>  When I need certain resources exposed during a long running 
>>>>>>> transaction, I
>>>>>>> transfer that data to a different Session and commit() those changes
>>>>>>> distinctly.
>>>>>>>
>>>>>>> My current needs would tend to use the short transactions for things
>>>>>> that are mostly
>>>>>> isolated from anything going on in the longer running (main)
>>>>>> transaction, though I do
>>>>>> suspect I might need what you mention in your last sentence, but
>>>>>> might you be able
>>>>>> to refer me to an example of how it would work, perchance?
>>>>>>
>>>>>>
>>>>>> I'd advise against going this route, you'd pretty much need to use
>>>>>> MySQL MyISAM tables to get guaranteed "dirty reads", that is, there's no
>>>>>> transaction at all, and it's not really how transactions were meant to be
>>>>>> used.    Lowering the isolation level is usually just a means to get more
>>>>>> transaction throughput.
>>>>>>
>>>>>
>>>>> Okay, I suspect I misunderstood what was being mentioned here, which is
>>>>> no problem; I'll avoid it. :)  Thanks once again for all the help.
>>>>>
>>>>> -Ken
>>>>>
>>>>>
>>>>>>
>>>>>> --
>>>>>> 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.
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> - Ken Lareau
>>>>>
>>>>>
>>>>> --
>>>>> 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.
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> 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.
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> - Ken Lareau
>>>>
>>>>
>>>
>>>
>>> --
>>> - Ken Lareau
>>>
>>>
>>> --
>>> 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.
>>>
>>>
>>>
>>> --
>>> 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.
>>>
>>
>>
>>
>> --
>> - Ken Lareau
>>
>>
>> --
>> 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.
>>
>>
>>
>> --
>> 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.
>>
>
>
>
> --
> - Ken Lareau
>
>
> --
> 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.
>
>
>  --
> 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.
>



-- 
- Ken Lareau

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