[Zope3-dev] ZopePublication performs auth outside
transaction
Phillip J. Eby
pje@telecommunity.com
Fri, 25 Apr 2003 18:25:40 -0400
At 05:43 PM 4/25/03 -0400, Shane Hathaway wrote:
>get_transaction() is helpful for multi-threaded applications,
As compared to what? If specifying a transaction manager is how you open a
connection, then why would you need get_transaction()?
>but a burden for simple event-driven applications. It could be a big
>burden for complex event-driven applications where it's difficult to know
>the right places to call suspend()/resume(). In a GUI application, for
>example, there is usually no particular entry point for handling events;
>event handlers are spread all over the code. Thus, many event-driven
>applications should not use get_transaction()--it just adds complexity.
>
>But the lines aren't always so clear. Some applications will combine the
>thread model with the event-driven model, especially as people add things
>to Zope 3. When event-driven code calls code that assumes threads and
>uses get_transaction(), the event-driven code should set the current
>transaction (to match an existing transaction) and clear the current
>transaction when the call is finished. In fact, there also ought to be
>something like "set_no_transaction()" that causes get_transaction() to fail.
Note that all this would be avoided by putting the knowledge of the
transaction in the connection. Then, event driven code working with
persistent objects from a given connection has a well-defined association
with a transaction -- regardless of what thread the GUI event runs in!
>You could implement what I just described using resume() to set the
>current transaction and suspend() to clear it. That's not a very obvious
>interface, but it would work.
>
>FWIW, here's an unbaked example of a simple GUI class that uses transactions:
>
>
>class MyDialog(Dialog):
>
> def __init__(self, db):
> self.conn = db.open()
> self.conn.setLocalTransaction()
> self.data = conn['MyApp'].dialog_data
>
> def onClickedChoice1RadioButton(self, event):
> self.data.choice1 = event.button.getValue()
>
> def onClickedChoice2Checkbox(self, event):
> self.data.choice2 = event.button.getValue()
>
> def onClickedOk(self, event):
> self.conn.getTransaction().commit()
> self.close()
>
> def onClickedCancel(self, event):
> self.conn.getTransaction().abort()
> self.close()
>
>
>If this had to use get_transaction(), each of the 4 event handlers would
>have to resume() and suspend() to avoid getting mixed up with simultaneous
>dialogs and/or windows. The GUI framework might provide a way to invoke
>some code before and after all event handlers, but it might not, and it's
>cleaner to just not have to do that.
What I'm proposing is that (in effect), the 'db.open()' above would require
a transaction as an input parameter. So you'd spell it:
self.conn = db.open(TransactionService())
or something like that, if you wanted to create a new transaction and
didn't need to keep a reference to it. (I like the 'conn.getTransaction()'
method; it makes sense as a way of passing fewer objects around.)