[Checkins] SVN: z3c.zalchemy/trunk/src/z3c/zalchemy/ Changed how
the two phase commit works.
Jürgen Kartnaller
juergen at kartnaller.at
Sun Mar 11 16:04:02 EDT 2007
Log message for revision 73142:
Changed how the two phase commit works.
This is how the two phase commit is used in zope.
1. tpc_begin(txn)
2. commit(txn)
3. tpc_vote(txn)
4. tpc_finish(txn)
What zalchemy is doing:
- commit does a session.flush() which actually executes all sql statements.
- tpc_finish() does a transaction.commit() in the sqlalchemy transaction
- tpc_abort() does a transaction.rollback() in the sqlalchemy transaction
If commit fails or another DataManager fails, data is not commited to the
database.
Thanks to Michael Bayer (the author of sqlalchemy) who gave me the hint to
integrate sqlalchemy correctly into the two phase commit.
Changed:
U z3c.zalchemy/trunk/src/z3c/zalchemy/README.txt
U z3c.zalchemy/trunk/src/z3c/zalchemy/datamanager.py
U z3c.zalchemy/trunk/src/z3c/zalchemy/tests/TRANSACTION.txt
-=-
Modified: z3c.zalchemy/trunk/src/z3c/zalchemy/README.txt
===================================================================
--- z3c.zalchemy/trunk/src/z3c/zalchemy/README.txt 2007-03-11 17:56:47 UTC (rev 73141)
+++ z3c.zalchemy/trunk/src/z3c/zalchemy/README.txt 2007-03-11 20:04:02 UTC (rev 73142)
@@ -10,7 +10,23 @@
transaction into the Zope transaction. This is solved by using a data manager
which joins the Zope transaction for every newly created thread.
+zalchemy uses the two phase commit system from zope.
+This is how the two phase commit is used in zope.
+
+ 1. tpc_begin(txn)
+ 2. commit(txn)
+ 3. tpc_vote(txn)
+ 4. tpc_finish(txn)
+
+ - commit does a session.flush() which actually executes all sql statements.
+ - tpc_finish() does a transaction.commit() in the sqlalchemy transaction
+ - tpc_abort() does a transaction.rollback() in the sqlalchemy transaction
+
+If commit fails or another DataManager fails data is not commited to the
+database.
+
+
Important
=========
Modified: z3c.zalchemy/trunk/src/z3c/zalchemy/datamanager.py
===================================================================
--- z3c.zalchemy/trunk/src/z3c/zalchemy/datamanager.py 2007-03-11 17:56:47 UTC (rev 73141)
+++ z3c.zalchemy/trunk/src/z3c/zalchemy/datamanager.py 2007-03-11 20:04:02 UTC (rev 73142)
@@ -176,6 +176,8 @@
"""
implements(IDataManager)
+ _commitFailed = False
+
def __init__(self, session):
self.session = session
self.transaction = session.create_transaction()
@@ -188,12 +190,13 @@
pass
def commit(self, trans):
- self.transaction.commit()
+ self.session.flush()
def tpc_vote(self, trans):
pass
def tpc_finish(self, trans):
+ self.transaction.commit()
_dataManagerFinished()
def tpc_abort(self, trans):
Modified: z3c.zalchemy/trunk/src/z3c/zalchemy/tests/TRANSACTION.txt
===================================================================
--- z3c.zalchemy/trunk/src/z3c/zalchemy/tests/TRANSACTION.txt 2007-03-11 17:56:47 UTC (rev 73141)
+++ z3c.zalchemy/trunk/src/z3c/zalchemy/tests/TRANSACTION.txt 2007-03-11 20:04:02 UTC (rev 73142)
@@ -156,3 +156,48 @@
>>> a.value == v
True
+
+Two Phase Commit With Errors
+----------------------------
+
+zalchemy uses zope's two phase commit by first doing only a flush when commit
+is called. SQLAlchemy's transaction is commited in the second phase of the
+zope transacion.
+
+ >>> session = z3c.zalchemy.getSession(True)
+ >>> aa=A()
+ >>> session.save(aa)
+ >>> aa.value = 3
+
+We create an object with an already existing primary key.
+
+ >>> aa.id = 2
+
+Let's make sure we get an exception when using commit.
+
+ >>> from z3c.zalchemy.datamanager import _storage
+ >>> _storage.dataManager.commit(transaction.manager.get())
+ Traceback (most recent call last):
+ ...
+ SQLError: (IntegrityError) PRIMARY KEY must be unique 'INSERT INTO table2 (id, value) VALUES (?, ?)' [2, 3]
+
+Finally we need to do an abort zope's transaction.
+
+ >>> transaction.abort()
+
+And we do the same using the commit from the transaction.
+
+ >>> session = z3c.zalchemy.getSession(True)
+ >>> aa=A()
+ >>> session.save(aa)
+ >>> aa.value = 3
+ >>> aa.id = 2
+ >>> transaction.commit()
+ Traceback (most recent call last):
+ ...
+ SQLError: (IntegrityError) PRIMARY KEY must be unique 'INSERT INTO table2 (id, value) VALUES (?, ?)' [2, 3]
+
+We need to manually abort the transaction.
+
+ >>> transaction.abort()
+
More information about the Checkins
mailing list