Index: trac/db/util.py
===================================================================
--- trac/db/util.py	(revision 8664)
+++ trac/db/util.py	(working copy)
@@ -15,6 +15,51 @@
 #
 # Author: Christopher Lenz <cmlenz@gmx.de>
 
+from __future__ import with_statement
+from contextlib import contextmanager
+
+@contextmanager
+def transaction(env, db, raise_exceptions = False):
+    """
+    Simple transaction context manager.
+    Usage:
+    -- def api_method(p1, p2):
+    --     with transaction(env, db) as cursor:
+    --         # implementation
+    --         result = data
+    --
+    """
+    dbtmp = db or env.get_db_cnx()
+    try:
+        yield dbtmp.cursor
+    except:
+        if not db: dbtmp.rollback()
+        if raise_exceptions: raise
+    else:
+        if not db: dbtmp.commit()
+
+@contextmanager
+def db_transaction(env, db, raise_exceptions = False):
+    """
+    Transaction context manager for more complicated code,
+    that needs access to the connection itself,
+    either for helper methods or to pass it along.
+    Usage:
+    -- def api_method(p1, p2):
+    --     with db_transaction(env, db) as db:
+    --         # implementation
+    --         result = data
+    --
+    """
+    dbtmp = db or env.get_db_cnx()
+    try:
+        yield dbtmp
+    except:
+        if not db: dbtmp.rollback()
+        if raise_exceptions: raise
+    else:
+        if not db: dbtmp.commit()
+
 def sql_escape_percent(sql):
     import re
     return re.sub("'((?:[^']|(?:''))*)'",
Index: trac/wiki/model.py
===================================================================
--- trac/wiki/model.py	(revision 8664)
+++ trac/wiki/model.py	(working copy)
@@ -16,6 +16,7 @@
 # Author: Jonas Borgström <jonas@edgewall.com>
 #         Christopher Lenz <cmlenz@gmx.de>
 
+from __future__ import with_statement
 import time
 from datetime import datetime
 
@@ -24,6 +25,7 @@
 from trac.util.datefmt import utc, to_timestamp
 from trac.util.translation import _
 from trac.wiki.api import WikiSystem
+from trac.db.util import transaction, db_transaction
 
 
 class WikiPage(object):
@@ -51,20 +53,21 @@
         self.old_readonly = self.readonly
 
     def _fetch(self, name, version=None, db=None):
-        if not db:
-            db = self.env.get_db_cnx()
-        cursor = db.cursor()
+        if not db: db = self.env.get_db_cnx()
+        cur = db.cursor()
         if version is not None:
-            cursor.execute("SELECT version,time,author,text,comment,readonly "
-                           "FROM wiki "
-                           "WHERE name=%s AND version=%s",
-                           (name, int(version)))
+            cur.execute("SELECT version,time,author,text,comment,readonly "
+                        "FROM wiki "
+                        "WHERE name=%s AND version=%s",
+                        (name, int(version)))
         else:
-            cursor.execute("SELECT version,time,author,text,comment,readonly "
-                           "FROM wiki "
-                           "WHERE name=%s ORDER BY version DESC LIMIT 1",
-                           (name,))
-        row = cursor.fetchone()
+            cur.execute("SELECT version,time,author,text,comment,readonly "
+                        "FROM wiki "
+                        "WHERE name=%s ORDER BY version DESC LIMIT 1",
+                        (name,))
+        row = cur.fetchone()
+
+        #import pdb; pdb.set_trace()
         if row:
             version,time,author,text,comment,readonly = row
             self.version = int(version)
@@ -83,37 +86,29 @@
 
     def delete(self, version=None, db=None):
         assert self.exists, 'Cannot delete non-existent page'
-        if not db:
-            db = self.env.get_db_cnx()
-            handle_ta = True
-        else:
-            handle_ta = False
+        with db_transaction(self.env, db) as db:
+            cur = db.cursor()
+            if version is None:
+                # Delete a wiki page completely
+                cur.execute("DELETE FROM wiki WHERE name=%s", (self.name,))
+                self.env.log.info('Deleted page %s' % self.name)
+            else:
+                # Delete only a specific page version
+                cur.execute("DELETE FROM wiki WHERE name=%s and version=%s",
+                            (self.name, version))
+                self.env.log.info('Deleted version %d of page %s'
+                                  % (version, self.name))
 
-        cursor = db.cursor()
-        if version is None:
-            # Delete a wiki page completely
-            cursor.execute("DELETE FROM wiki WHERE name=%s", (self.name,))
-            self.env.log.info('Deleted page %s' % self.name)
-        else:
-            # Delete only a specific page version
-            cursor.execute("DELETE FROM wiki WHERE name=%s and version=%s",
-                           (self.name, version))
-            self.env.log.info('Deleted version %d of page %s'
-                              % (version, self.name))
+            if version is None or version == self.version:
+                self._fetch(self.name, None, db)
 
-        if version is None or version == self.version:
-            self._fetch(self.name, None, db)
+            if not self.exists:
+                # Invalidate page name cache
+                WikiSystem(self.env).pages.invalidate(db)
+                # Delete orphaned attachments
+                from trac.attachment import Attachment
+                Attachment.delete_all(self.env, 'wiki', self.name, db)
 
-        if not self.exists:
-            # Invalidate page name cache
-            WikiSystem(self.env).pages.invalidate(db)
-            # Delete orphaned attachments
-            from trac.attachment import Attachment
-            Attachment.delete_all(self.env, 'wiki', self.name, db)
-
-        if handle_ta:
-            db.commit()
-
         # Let change listeners know about the deletion
         if not self.exists:
             for listener in WikiSystem(self.env).change_listeners:
@@ -125,38 +120,28 @@
 
 
     def save(self, author, comment, remote_addr, t=None, db=None):
-        if not db:
-            db = self.env.get_db_cnx()
-            handle_ta = True
-        else:
-            handle_ta = False
-
-        if t is None:
-            t = datetime.now(utc)
-
-        if self.text != self.old_text:
-            cursor = db.cursor()
-            cursor.execute("INSERT INTO wiki (name,version,time,author,ipnr,"
-                           "text,comment,readonly) VALUES (%s,%s,%s,%s,%s,%s,"
-                           "%s,%s)", (self.name, self.version + 1,
-                                      to_timestamp(t), author, remote_addr,
-                                      self.text, comment, self.readonly))
-            self.version += 1
-            self.resource = self.resource(version=self.version)
-        elif self.readonly != self.old_readonly:
-            cursor = db.cursor()
-            cursor.execute("UPDATE wiki SET readonly=%s WHERE name=%s",
-                           (self.readonly, self.name))
-        else:
+        new_text = self.text != self.old_text
+        if not new_text and self.readonly == self.old_readonly:
             raise TracError(_('Page not modified'))
+        t = t or datetime.now(utc)
 
-        if self.version == 1:
-            # Invalidate page name cache
-            WikiSystem(self.env).pages.invalidate(db)
-        
-        if handle_ta:
-            db.commit()
-
+        with db_transaction(self.env, db) as db:
+            cur = db.cursor()
+            if(new_text):
+                cur.execute("INSERT INTO wiki (name,version,time,author,ipnr,"
+                            "text,comment,readonly) VALUES (%s,%s,%s,%s,%s,%s,"
+                            "%s,%s)", (self.name, self.version + 1,
+                                       to_timestamp(t), author, remote_addr,
+                                       self.text, comment, self.readonly))
+                self.version += 1
+                self.resource = self.resource(version=self.version)
+            else:
+                cur.execute("UPDATE wiki SET readonly=%s WHERE name=%s",
+                            (self.readonly, self.name))
+            if self.version == 1:
+                # Invalidate page name cache
+                WikiSystem(self.env).pages.invalidate(db)
+                
         for listener in WikiSystem(self.env).change_listeners:
             if self.version == 1:
                 listener.wiki_page_added(self)
