Froschs Blog

Computer und was das Leben sonst noch so zu bieten hat

Zur Website | Impressum

Spaß mit Python3 und InnoDB

13. Januar 2022 um 0:59 Uhr von Atari-Frosch

Die Blogs, die ich betreibe bzw. administriere, laufen allesamt mit MariaDB, einem Fork von MySQL. Die beiden Datenbank-Systeme kennen zwei verschiedene Engines, um Daten zu verwalten: MyISAM (die ältere) und InnoDB (die neuere). Die Blogs, die ursprünglich mit WordPress gestartet waren, legten ihre Datenbank mit MyISAM an, und auch, wenn die Blogs mittlerweile auf ClassicPress umgestellt wurden, blieb dieses Format erhalten. Was ich neu direkt mit ClassicPress installiert habe, bekam jedoch eine Datenbank mit der InnoDB-Engine, die die Daten ein wenig anders ablegt. Im laufenden Betrieb insbesondere der relativ kleinen Blogs macht das erstmal keinen Unterschied.

Anders sieht das aus, wenn ich abseits vom Blogsystem (hier: mit Python3) in diese Datenbanken reingreifen möchte. Solange ich nur lesend reingehe, ist das weiterhin kein Problem. Will ich jedoch schreibend auf diese Datenbanken zugreifen, gibt es einen kleinen, feinen Unterschied, und der hat mich eine Weile beschäftigt.

Mit einem Script (via Cronjob) greife ich einmal am Tag in die Blog-Datenbanken und lese erstmal alle Spam-Kommentare und -Trackbacks aus. Diese wurden vorher vom Plugin Antispam-Bee erkannt und bereits als Spam markiert; das Plugin kann ich nur empfehlen, es hat bei mittlerweile über 100.000 Spams in allen meinen Blogs nicht ein einziges Mal einen legitimen Kommentar als Spam markiert, und umgekehrt ist die Anzahl der Spams, die ihm durchgegangen sind und in der Moderation landeten, im unteren zweistelligen Bereich.

Nach dem Auslesen der Daten, die ich weiterverarbeiten möchte, werden diese Kommentare und Trackbacks innerhalb des Blogsystems nicht mehr benötigt; es bietet sich also an, sie – da sie bereits identifiziert sind – dann auch direkt zu löschen. Das ist ein schreibender Zugriff. Und da stieß ich auf ein interessantes Phänomen:

Obwohl ich mit demselben Script in alle Blog-Datenbanken gehe, gab es einen Ausreißer: Im direkt mit ClassicPress installierten Blog dokufotos.biz wurden die Spams nicht gelöscht, obwohl ich nirgends eine Fehlermeldung finden konnte. Das Script selbst lasse ich auch loggen, und es sagte mir: Jou, hab gelöscht – aber die Kommentare waren weiterhin in der Datenbank. Das führte dazu, daß immer wieder dieselben Spam-Kommentare und -Trackbacks ausgelesen wurden, was ja nicht Sinn der Sache war.

Wie üblich, wenn ich wo nicht weiterkomme, habe ich – in diesem Fall mehrfach – im Netz herumgefragt.

Zunächst im Diaspora-Netzwerk am 20. November: Python3 und mysql.

Da habe ich auch das Code-Schnipsel mit drin, das die Daten löschen soll:

commentstable = config.tableprefix[blogid] + "_comments"
# […]
    for h in commentids:
        sql = "DELETE FROM " + commentstable + " WHERE comment_ID = " + str(h)
        logging.debug("sql statement: %s", sql)
        db = pymysql.connect(dbhost, dbuser, dbpass, dbname)
        cursor = db.cursor()
        cursor.execute(sql)
        data = cursor.fetchall()
        db.close()

commentids ist eine Liste, in die ich vorher die IDs der als Spam markierten Kommentare und Trackbacks eingelesen habe. Witzig ist, daß das Statement so, wie ich es hier zusammenbaue, direkt im MariaDB-Interpreter (CLI) anstandslos und erfolgreich ausgeführt wird, von Python aus jedoch nicht.

Ich hatte dort auch bereits festgestellt:

Das vorherige Abrufen der Kommentare funktioniert! Das heißt: Die Tabelle wird vorher korrekt angesprochen, und auch die Kommentar-IDs sind korrekt. Nur gelöscht werden diese Kommentare dann nicht, das heißt, ich hab sie jeden Tag wieder mit in der Liste der abgerufenen Spams. So ist das ja nicht gedacht. Auch der Log-Eintrag, der hier nach dem Statement vorgesehen ist, wird für das betroffene Blog nicht geschrieben (der Loglevel ist für alle gleich auf 5 gesetzt).

Dann waren jedoch wieder andere Dinge wichtiger, und das Problem blieb erstmal liegen.

Letzten Donnerstag fragte ich dann mal im Python-Foo des Chaosdorfs. Dort bekam ich den Hinweis, daß ich mich mal mit dem Locking in InnoDB auseinandersetzen sollte. Aber mein Abstrakt-zu-Konkret-auflösen-Problem war beim Verstehen entsprechender Erklärungstexte mal wieder, ähm, nicht hilfreich. Schließlich stieß ich beim Weitersuchen auf eine Funktion im von mir verwendeten Python3-Modul pymysql:

db.commit()

Gelernt: Es genügt bei einer Datenbank im InnoDB-Format nicht, von Python aus ein SQL-Statement hinzuschicken, um Daten zu verändern; man muß der Datenbank auch noch explizit sagen, daß die Statements jetzt bitteschön auch noch ausgeführt werden sollen. Bislang hatte ich das so verstanden, daß das mit cursor.execute(sql) erreicht wird. Offenbar ist dem doch nicht so.

Den zusätzlichen Befehl stellte ich vor die Zeile mit db.close().

Was soll ich sagen: Schwups, waren die Kommentare auch vom Script aus gelöscht 🙂

Bei MyISAM-Datenbanken ist die zusätzliche Commit-Anweisung offenbar nicht notwendig, daher stand sie auch nicht in meinem Script. Umgekehrt scheint es die Datenbanken im MyISAM-Format nicht zu stören, daß da jetzt noch ein Commit hinterherkommt, denn bei denen funktioniert das Script weiterhin wie bisher.

Wieder ein Problem gelöst. 🤓


History

Ein Kommentar zu “Spaß mit Python3 und InnoDB”

  1. Michael Richter quakte:

    Das erstere Verhalten nennt sich bei Oracle Autocommit, aber damit ist natürlich kein Statement-übergreifendes ACID möglich.


Kommentieren

Bitte beachte die Kommentarregeln!

XHTML: Du kannst diese Tags verwenden: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>