Index: announcer/api.py
===================================================================
--- announcer/api.py	(revision 10191)
+++ announcer/api.py	(working copy)
@@ -407,7 +407,8 @@
     # IEnvironmentSetupParticipant methods
 
     def environment_created(self):
-        self._upgrade_db(self.env.get_db_cnx())
+	with self.env.db_transaction as db:
+	    self._upgrade_db(db)
 
     def environment_needs_upgrade(self, db):
         schema_ver = self.get_schema_version(db)
@@ -427,43 +428,43 @@
 
     def get_schema_version(self, db=None):
         """Return the current schema version for this plugin."""
-        db = db and db or self.env.get_db_cnx()
-        cursor = db.cursor()
-        cursor.execute("""
-            SELECT value
-              FROM system
-             WHERE name='announcer_version'
-        """)
-        row = cursor.fetchone()
-        if not (row and int(row[0]) > 5):
-            # Care for pre-announcer-1.0 installations.
-            dburi = self.config.get('trac', 'database')
-            tables = self._get_tables(dburi, cursor)
-            if 'subscription' in tables:
-                # Version > 2
-                cursor.execute("SELECT * FROM subscription_attribute")
-                columns = [col[0] for col in cursor.cursor.description]
-                if 'authenticated' in columns:
-                    self.log.debug("TracAnnouncer needs to register schema "
-                                   "version")
-                    return 5
-                if 'realm' in columns:
-                    self.log.debug("TracAnnouncer needs to change a table")
-                    return 4
-                self.log.debug("TracAnnouncer needs to change tables")
-                return 3
-            if 'subscriptions' in tables:
-                cursor.execute("SELECT * FROM subscriptions")
-                columns = [col[0] for col in cursor.cursor.description]
-                if 'format' not in columns:
-                    self.log.debug("TracAnnouncer needs to add new tables")
-                    return 2
-                self.log.debug("TracAnnouncer needs to add/change tables")
-                return 1
-            # This is a new installation.
-            return 0
-        # The expected outcome for any up-to-date installation.
-        return row and int(row[0]) or 0
+	with self.env.db_query as db:
+	    cursor = db.cursor()
+	    cursor.execute("""
+		SELECT value
+		  FROM system
+		 WHERE name='announcer_version'
+	    """)
+	    row = cursor.fetchone()
+	    if not (row and int(row[0]) > 5):
+		# Care for pre-announcer-1.0 installations.
+		dburi = self.config.get('trac', 'database')
+		tables = self._get_tables(dburi, cursor)
+		if 'subscription' in tables:
+		    # Version > 2
+		    cursor.execute("SELECT * FROM subscription_attribute")
+		    columns = [col[0] for col in cursor.cursor.description]
+		    if 'authenticated' in columns:
+			self.log.debug("TracAnnouncer needs to register schema "
+				       "version")
+			return 5
+		    if 'realm' in columns:
+			self.log.debug("TracAnnouncer needs to change a table")
+			return 4
+		    self.log.debug("TracAnnouncer needs to change tables")
+		    return 3
+		if 'subscriptions' in tables:
+		    cursor.execute("SELECT * FROM subscriptions")
+		    columns = [col[0] for col in cursor.cursor.description]
+		    if 'format' not in columns:
+			self.log.debug("TracAnnouncer needs to add new tables")
+			return 2
+		    self.log.debug("TracAnnouncer needs to add/change tables")
+		    return 1
+		# This is a new installation.
+		return 0
+	    # The expected outcome for any up-to-date installation.
+	    return row and int(row[0]) or 0
 
     @staticmethod
     def _get_tables(dburi, cursor):
Index: announcer/opt/tests/subscribers.py
===================================================================
--- announcer/opt/tests/subscribers.py	(revision 10191)
+++ announcer/opt/tests/subscribers.py	(working copy)
@@ -31,8 +31,8 @@
             enable=['trac.*', 'announcer.opt.subscribers.*'])
         self.env.path = tempfile.mkdtemp()
         self.db_mgr = DatabaseManager(self.env)
-        self.db = self.env.get_db_cnx()
-        AnnouncementSystem(self.env).upgrade_environment(self.db)
+	with env.db_transaction as self.db:
+	    AnnouncementSystem(self.env).upgrade_environment(self.db)
 
     def tearDown(self):
         self.env.db_transaction("DROP table 'subscription'")
Index: announcer/tests/subscribers.py
===================================================================
--- announcer/tests/subscribers.py	(revision 10191)
+++ announcer/tests/subscribers.py	(working copy)
@@ -26,7 +26,7 @@
             enable=['trac.*', 'announcer.subscribers.*'])
         self.env.path = tempfile.mkdtemp()
         self.db_mgr = DatabaseManager(self.env)
-        self.db = self.env.get_db_cnx()
+        self.db = self.env.db_transaction
 
     def tearDown(self):
         self.db.close()
Index: announcer/tests/api.py
===================================================================
--- announcer/tests/api.py	(revision 10191)
+++ announcer/tests/api.py	(working copy)
@@ -49,7 +49,7 @@
         self.env = EnvironmentStub(enable=['trac.*'])
         self.env.path = tempfile.mkdtemp()
         self.db_mgr = DatabaseManager(self.env)
-        self.db = self.env.get_db_cnx()
+        self.db = self.env.db_transaction
         self.an_sys = AnnouncementSystem(self.env)
 
     def tearDown(self):
@@ -463,7 +463,7 @@
         self.env = EnvironmentStub(enable=['trac.*'])
         self.env.path = tempfile.mkdtemp()
         self.db_mgr = DatabaseManager(self.env)
-        self.db = self.env.get_db_cnx()
+        self.db = self.env.db_transaction
 
     def tearDown(self):
         self.db.close()
@@ -482,7 +482,7 @@
         self.env = EnvironmentStub(enable=['trac.*', 'announcer.*'])
         self.env.path = tempfile.mkdtemp()
         self.db_mgr = DatabaseManager(self.env)
-        self.db = self.env.get_db_cnx()
+        self.db = self.env.db_transaction
         self.an_sys = AnnouncementSystem(self.env)
 
     def tearDown(self):
Index: announcer/tests/pref.py
===================================================================
--- announcer/tests/pref.py	(revision 10191)
+++ announcer/tests/pref.py	(working copy)
@@ -23,7 +23,7 @@
         self.env = EnvironmentStub(enable=['trac.*'])
         self.env.path = tempfile.mkdtemp()
         self.db_mgr = DatabaseManager(self.env)
-        self.db = self.env.get_db_cnx()
+        self.db = self.env.db_transaction
 
     def tearDown(self):
         self.db.close()
Index: announcer/tests/model.py
===================================================================
--- announcer/tests/model.py	(revision 10191)
+++ announcer/tests/model.py	(working copy)
@@ -22,7 +22,7 @@
         self.env = EnvironmentStub(enable=['trac.*'])
         self.env.path = tempfile.mkdtemp()
         self.db_mgr = DatabaseManager(self.env)
-        self.db = self.env.get_db_cnx()
+        self.db = self.env.db_transaction
         # Setup current announcer db schema tables.
         self.an_sys = AnnouncementSystem(self.env)
         self.an_sys.upgrade_environment(self.db)
Index: announcer/upgrades/db4.py
===================================================================
--- announcer/upgrades/db4.py	(revision 10191)
+++ announcer/upgrades/db4.py	(working copy)
@@ -57,26 +57,26 @@
     for table in schema:
         for stmt in connector.to_sql(table):
             cursor.execute(stmt)
-    db = env.get_db_cnx()
-    # Convert priority values to integer.
-    cursor.execute("""
-        INSERT INTO subscription
-               (time,changetime,class,sid,authenticated,
-                distributor,format,priority,adverb)
-        SELECT o.time,o.changetime,o.class,o.sid,o.authenticated,
-               o.distributor,o.format,%s,o.adverb
-          FROM subscription_old AS o
-        """ % db.cast('o.priority', 'int'))
-    cursor.execute("DROP TABLE subscription_old")
+    with env.db_transaction as db:
+	# Convert priority values to integer.
+	cursor.execute("""
+	    INSERT INTO subscription
+		   (time,changetime,class,sid,authenticated,
+		    distributor,format,priority,adverb)
+	    SELECT o.time,o.changetime,o.class,o.sid,o.authenticated,
+		   o.distributor,o.format,%s,o.adverb
+	      FROM subscription_old AS o
+	    """ % db.cast('o.priority', 'int'))
+	cursor.execute("DROP TABLE subscription_old")
 
-    # Copy table on column name change.
-    cursor.execute("""
-        INSERT INTO subscription_attribute
-               (sid,class,realm,target)
-        SELECT o.sid,o.class,o.name,o.value
-          FROM subscription_attribute_old AS o
-    """)
-    cursor.execute("DROP TABLE subscription_attribute_old")
+	# Copy table on column name change.
+	cursor.execute("""
+	    INSERT INTO subscription_attribute
+		   (sid,class,realm,target)
+	    SELECT o.sid,o.class,o.name,o.value
+	      FROM subscription_attribute_old AS o
+	""")
+	cursor.execute("DROP TABLE subscription_attribute_old")
 
-    # DEVEL: Migrate old subscription db table data.
-    cursor.execute("DROP TABLE IF EXISTS subscriptions")
+	# DEVEL: Migrate old subscription db table data.
+	cursor.execute("DROP TABLE IF EXISTS subscriptions")
Index: announcer/resolvers.py
===================================================================
--- announcer/resolvers.py	(revision 10191)
+++ announcer/resolvers.py	(working copy)
@@ -35,19 +35,19 @@
     implements(IAnnouncementAddressResolver)
 
     def get_address_for_name(self, name, authenticated):
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
-        cursor.execute("""
-            SELECT value
-              FROM session_attribute
-             WHERE sid=%s
-               AND authenticated=%s
-               AND name=%s
-        """, (name, int(authenticated), 'email'))
-        result = cursor.fetchone()
-        if result:
-            return result[0]
-        return None
+	with self.env.db_query as db:
+	    cursor = db.cursor()
+	    cursor.execute("""
+		SELECT value
+		  FROM session_attribute
+		 WHERE sid=%s
+		   AND authenticated=%s
+		   AND name=%s
+	    """, (name, int(authenticated), 'email'))
+	    result = cursor.fetchone()
+	    if result:
+		return result[0]
+	    return None
 
 
 class SpecifiedEmailResolver(Component):
@@ -55,19 +55,19 @@
     implements(IAnnouncementAddressResolver, IAnnouncementPreferenceProvider)
 
     def get_address_for_name(self, name, authenticated):
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
-        cursor.execute("""
-            SELECT value
-              FROM session_attribute
-             WHERE sid=%s
-               AND authenticated=1
-               AND name=%s
-        """, (name, 'announcer_specified_email'))
-        result = cursor.fetchone()
-        if result:
-            return result[0]
-        return None
+	with env.db_query as db:
+	    cursor = db.cursor()
+	    cursor.execute("""
+		SELECT value
+		  FROM session_attribute
+		 WHERE sid=%s
+		   AND authenticated=1
+		   AND name=%s
+	    """, (name, 'announcer_specified_email'))
+	    result = cursor.fetchone()
+	    if result:
+		return result[0]
+	    return None
 
     # IAnnouncementDistributor methods
 
Index: announcer/util/settings.py
===================================================================
--- announcer/util/settings.py	(revision 10191)
+++ announcer/util/settings.py	(working copy)
@@ -48,8 +48,8 @@
 
     def get_user_setting(self, sid):
         """Returns tuple of (value, authenticated)."""
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
+with env.db_query as db:
+            cursor = db.cursor()
         cursor.execute("""
             SELECT value, authenticated
               FROM session_attribute
@@ -77,19 +77,19 @@
         Tuples are suitable for yielding from IAnnouncementSubscriber's
         subscriptions method.
         """
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
-        cursor.execute("""
-            SELECT sid, authenticated, value
-              FROM session_attribute
-             WHERE name=%s
-        """, (self._attr_name(),))
-        for result in cursor.fetchall():
-            dists, val = decode(result[2])
-            for dist in dists:
-                if match(dist, val):
-                    authenticated = istrue(result[1])
-                    yield (dist, result[0], authenticated, None)
+	with env.db_query as db:
+	    cursor = db.cursor()
+	    cursor.execute("""
+		SELECT sid, authenticated, value
+		  FROM session_attribute
+		 WHERE name=%s
+	    """, (self._attr_name(),))
+	    for result in cursor.fetchall():
+		dists, val = decode(result[2])
+		for dist in dists:
+		    if match(dist, val):
+			authenticated = istrue(result[1])
+			yield (dist, result[0], authenticated, None)
 
     def _attr_name(self):
         return 'sub_%s' % self.name
@@ -128,27 +128,27 @@
         Value is always True or None.  This will work with Genshi template
         checkbox logic.
         """
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
-        cursor.execute("""
-            SELECT value, authenticated
-              FROM session_attribute
-             WHERE sid=%s
-               AND name=%s
-        """, (sid, self._attr_name()))
-        row = cursor.fetchone()
-        if row:
-            dists, v = decode(row[0])
-            value = istrue(v)
-            authenticated = istrue(row[1])
-        else:
-            dists = self.default['dists']
-            value = istrue(self.default['value'])
-            authenticated = False
+	with env.db_query as db:
+	    cursor = db.cursor()
+	    cursor.execute("""
+		SELECT value, authenticated
+		  FROM session_attribute
+		 WHERE sid=%s
+		   AND name=%s
+	    """, (sid, self._attr_name()))
+	    row = cursor.fetchone()
+	    if row:
+		dists, v = decode(row[0])
+		value = istrue(v)
+		authenticated = istrue(row[1])
+	    else:
+		dists = self.default['dists']
+		value = istrue(self.default['value'])
+		authenticated = False
 
-        # We use None here so that Genshi templates check their checkboxes
-        # properly and without confusion.
-        return dists, value and True or None, authenticated
+	    # We use None here so that Genshi templates check their checkboxes
+	    # properly and without confusion.
+	    return dists, value and True or None, authenticated
 
     def get_subscriptions(self):
         """Generates tuples of (distributor, sid, authenticated, email).
@@ -156,19 +156,19 @@
         Tuples are suitable for yielding from IAnnouncementSubscriber's
         subscriptions method.
         """
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
-        cursor.execute("""
-            SELECT sid, authenticated, value
-              FROM session_attribute
-             WHERE name=%s
-        """, (self._attr_name(),))
-        for result in cursor.fetchall():
-            dists, val = decode(result[2])
-            for dist in dists:
-                if istrue(val):
-                    authenticated = istrue(result[1])
-                    yield (dist, result[0], authenticated, None)
+	with env.db_query as db:
+	    cursor = db.cursor()
+	    cursor.execute("""
+		SELECT sid, authenticated, value
+		  FROM session_attribute
+		 WHERE name=%s
+	    """, (self._attr_name(),))
+	    for result in cursor.fetchall():
+		dists, val = decode(result[2])
+		for dist in dists:
+		    if istrue(val):
+			authenticated = istrue(result[1])
+			yield (dist, result[0], authenticated, None)
 
     def _attr_name(self):
         return 'sub_%s' % self.name
