Python und DB: DBI-Cursor verstehen

Ich habe den "Cursor" untersucht, der beim Betrieb der Datenbank mit Python angezeigt wird, da er zu unbekannt ist. Wir haben psycopg2 für PostgreSQL und MySQLdb für MySQL unter dem Gesichtspunkt des Unterschieds zwischen SQL CURSOR und Python-Cursor und der genauen Implementierung von SQL CURSOR untersucht.

Frage

Fazit

Der Text ist lang, also aus der Schlussfolgerung.

  1. Python Cursor hat ungefähr drei Arten von Implementierungen.
  1. In psycopg2 für PostgreSQL ist das Deklarieren eines ** benannten Cursors ** serverseitig. Es wäre clientseitig ohne Namen.
  2. MySQLdb für MySQL ist nur clientseitig.

Implementierung des Python-Cursors

Art DB DBI Cursor-Deklarationsmethode
Serverseite PostgreSQL psycopg2 cursor('Name')
Client-Seite(Mit Puffer) PostgreSQL psycopg2 cursor()
Client-Seite(Mit Puffer) MySQL MySQLdb cursor()
Client-Seite(Kein Puffer) MySQL MySQLdb connect( cursorclass = MySQLdb.cursors.SSCursor )Als Cursor()

Korrespondenztabelle von SQL CURSOR und Python-Cursor

Die Beziehung zwischen dem serverseitigen Cursor ("SSC") und der Python-Methode ist wie folgt: Sofern nicht anders angegeben, kann es nicht mit dem clientseitigen Cursor ("CSC") verwendet werden.

SQL Python Bemerkungen
DECLARE CURSOR name Cursor in psycopg2('name') Je nach Treiberimplementierung nicht standardisiert. Eine der Schwächen von Python.
FETCH NEXT fetchone() Stickerei in CSC
FETCH FORWARD n fetchmany(n) Stickerei in CSC
FETCH ALL fetchall() Stickerei in CSC
FETCH PRIOR Unzutreffend scroll(-2, mode='relative'); fetchone()Kann durch ersetzt werden
FETCH FIRST Unzutreffend scroll(-1, mode='absolute'); fetchone()Kann durch ersetzt werden
FETCH LAST Unzutreffend scroll(-2, mode='absolute'); fetchone()Kann durch ersetzt werden
MOVE mode value scroll(value, mode) In CSC wird es zur Emulation, und Sie können nur vorwärts gehen. Ich erhalte eine NotSupportedError-Ausnahme, wenn ich versuche, zurückzukehren.
CURRENT OF Äquivalent Verweis auf Cursorzeile

Umfrage

Ich habe SQL CURSOR und Python Cursor untersucht.

SQL CURSOR

Der Cursor kann die Ergebnisse von Abfragen wie SELECT-Anweisungen einzeln abrufen oder zur vorherigen oder nächsten Zeile wechseln. Sie können auch aus anderen SQL-Anweisungen auf die aktuelle Zeile verweisen. Die Details werden weggelassen, da der Zweck nicht darin besteht, die Grammatik zu erklären.

Deklaration des Cursors

Der Cursor wird so deklariert.

DECLARE Cursorname CURSOR FOR SELECT Anweisung

Holen Sie sich Reihe

Führen Sie eine Anweisung ähnlich der folgenden aus, um die nächste Zeile des Cursors zu erhalten: Die normale Richtung ist "NEXT" oder "FORWARD", um die Reihe zu erhalten, während Sie sich vorwärts bewegen. Es ist auch möglich, in der Mitte zurückzukehren. In diesem Fall geben Sie "PRIOR" oder "BACKWARD" an. Es ist auch möglich, gleichzeitig zum Anfang "ERST" oder zum Ende "LETZT" zu wechseln.

FETCH-Richtung VON Cursorname

Bewegen Sie den Cursor

Verwenden Sie MOVE, wenn Sie sich nur bewegen möchten, ohne eine Zeile zu erhalten. Die Richtungsspezifikation ist dieselbe wie bei FETCH.

Verschieben Sie die Richtung vom Cursornamen

Verweis auf Cursorzeile

Sie können auch auf die Cursorzeile anderer Anweisungen verweisen. In diesem Fall können Sie problemlos andere Vorgänge ausführen, während Sie das Ergebnis von SELECT verwenden. Verwenden Sie beispielsweise "CURRENT OF" wie folgt, um eine Zeile anzuzeigen, in der gerade ein Cursor abgerufen wird:

UPDATE names SET name='tomochi'WO AKTUELLER Cursorname

Python cursor

cursor wird durch Aufrufen der .cursor () -Methode des Verbindungsobjekts erstellt. Transaktionen funktionieren für Verbindungsobjekte. Wenn Sie also mehrere Cursor aus einem Verbindungsobjekt erstellen, werden diese innerhalb einer Transaktion ausgeführt.

Cursormethode (Teil)

Es werden nur die Methoden behandelt, die wahrscheinlich mit SQL CURSOR zusammenhängen.

Experiment

Experimentieren Sie, um festzustellen, ob der Python-Cursor SQL CURSOR deklariert und verwendet. Die Methode ist Aktivieren Sie die Anweisungsprotokollierung in PostgreSQL bzw. MySQL, führen Sie normale Cursor und benannte Cursor aus und vergleichen Sie die tatsächlich ausgegebenen SQL-Anweisungen.

PostgreSQL + psycopg2 Starten Sie mit log_statement = 'all' in postgresql.conf neu. Erstellen Sie eine entsprechende PostgreSQL-Datenbank und legen Sie die Tabelle und die Testdaten darin ab.

names.sql


CREATE TABLE names (
  name varchar(100)
);

INSERT INTO names VALUES ('kenji');
INSERT INTO names VALUES ('keigo');

Namenloser Cursor

psql1.py


import psycopg2
conn = psycopg2.connect(database='kenji')
cu = conn.cursor()
cu.execute('SELECT * FROM names')
print cu.fetchone()
conn.close()

Das Ergebnis lautet wie folgt: Auf der Serverseite gibt es keine Deklaration des Cursors, und alle Zeilen werden abgerufen.

LOG:  statement: BEGIN
LOG:  statement: SELECT * FROM names

Benannter Cursor

Versuchen Sie als nächstes SELECT mit dem benannten Cursor auf die gleiche Weise. Der einzige Unterschied zu dem oben genannten ist der Name von cursor ().

psql2.py


import psycopg2
conn = psycopg2.connect(database='kenji')
cu = conn.cursor('foo')
cu.execute('SELECT * FROM names')
print cu.fetchone()
conn.close()

Das Ergebnis zeigt, dass der Cursor auf der Serverseite deklariert ist und FETCH ausgeführt wird.

LOG:  statement: BEGIN
LOG:  statement: DECLARE "foo" CURSOR WITHOUT HOLD FOR SELECT * FROM names
LOG:  statement: FETCH FORWARD 1 FROM "foo"

MySQL + MySQLdb Fügen Sie die folgende Zeile zum Abschnitt [mysqld] in my.cnf hinzu und starten Sie neu.

general_log_file        = /var/log/mysql/mysql.log
general_log             = 1

Normaler Cursor

msql1.py


import MySQLdb
conn = MySQLdb.connect(db='kenji', user='kenji')
cu = conn.cursor()
cu.execute('SELECT * FROM names')
print cu.fetchone()
conn.close()

Das Ergebnis ist erwartungsgemäß ein einfaches cursorloses SELECT.

Connect	kenji@localhost on kenji
Query	set autocommit=0
Query	SELECT * FROM names
Quit

SSCursor Als nächstes experimentieren wir mit der Cursor-Klasse, die im MySQLdb-Handbuch als "serverseitiger Cursor" beschrieben wird. Es wird aktiviert, indem cursorclass = MySQLdb.cursors.SSCursor an connect () übergeben wird.

msql2.py


import MySQLdb
import MySQLdb.cursors
conn = MySQLdb.connect(db='kenji', user='kenji',
                       cursorclass = MySQLdb.cursors.SSCursor)
cu = conn.cursor()
cu.execute('SELECT * FROM names')
print cu.fetchone()
conn.close()

Das Ergebnis ist das gleiche wie bei einem normalen Cursor. Es wurde kein serverseitiger Cursor deklariert.

Connect	kenji@localhost on kenji
Query	set autocommit=0
Query	SELECT * FROM names
Quit

Wenn ich die Quelle lese, ist es eine überraschende Implementierung, die blockiert, indem keine Daten aus dem Socket gelesen werden. Wäre es nicht möglich, andere Anweisungen auszuführen, wenn sie auf Verbindungsebene blockiert wären? Die Namenstabelle enthält zwei Zeilen. Was passiert jedoch, wenn ich die erste Zeile erhalte und sie dann separat auswähle?

msql3.py


import MySQLdb
import MySQLdb.cursors
conn = MySQLdb.connect(db='kenji', user='kenji',
                       cursorclass = MySQLdb.cursors.SSCursor)
cu1 = conn.cursor()
cu2 = conn.cursor()
cu1.execute('SELECT name as name1 FROM names')
print "CU1", cu1.fetchone()
cu2.execute('SELECT name as name2 FROM names')
print "CU2", cu2.fetchone()
conn.close()

Die Hinrichtung wurde abgelehnt.

$ python msql3.py
CU1 ('kenji',)
Traceback (most recent call last):
  File "msql3.py", line 9, in <module>
    cu2.execute('SELECT name as name2 FROM names')
  File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now")
Exception _mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now") in <bound method SSCursor.__del__ of <MySQLdb.cursors.SSCursor object at 0x7f6d9b542f50>> ignored
Exception _mysql_exceptions.ProgrammingError: (2014, "Commands out of sync; you can't run this command now") in <bound method SSCursor.__del__ of <MySQLdb.cursors.SSCursor object at 0x7f6d9b542e50>> ignored

"Sie können diesen Befehl jetzt nicht ausführen". Ich verstehe das MySQL Connector (Client Library) Handbuch nicht vollständig, aber irgendwie die Ergebnisse Es scheint, dass die nächste Anweisung nicht im selben Thread ausgeführt werden kann, da sie nicht vollständig gelesen wurde. Es befindet sich in einem Zustand, in dem es gelesen, aber nicht aus anderen Threads geschrieben werden kann. SSCursor ist nutzlos.

Verweis auf den serverseitigen Cursor

Verwenden Sie in PostgreSQL einen serverseitigen Cursor und einen regulären Cursor. Navigieren Sie zum serverseitigen Cursor. Ein sehr einfaches Beispiel für die Aktualisierung von 'kenji' in der Namenstabelle auf 'tomochi'.

psycopg2_named_cursor_example.py


import psycopg2

conn = psycopg2.connect(database='kenji')

cu1 = conn.cursor('foo')   #Serverseitiger Cursor 1
cu2 = conn.cursor()  #Normaler Cursor 2

#Sie müssen die Leitung nicht sperren, aber irgendwie.
cu1.execute("SELECT name FROM names WHERE name=%s FOR UPDATE;", ('kenji',))

print cu1.fetchone()

cu2.execute("UPDATE names SET name='tomochi' WHERE CURRENT OF foo;")   #UPDATE der aktuellen Zeile von Cursor 1
cu2.close()

conn.commit()
conn.close()

Das Ablaufverfolgungsprotokoll lautet wie folgt. Das SQL wird wie erwartet ausgeführt.

LOG:  statement: BEGIN
LOG:  statement: DECLARE "foo" CURSOR WITHOUT HOLD FOR SELECT name FROM names WHERE name='kenji' FOR UPDATE
LOG:  statement: FETCH FORWARD 1 FROM "foo"
LOG:  statement: UPDATE names SET name='tomochi' WHERE CURRENT OF foo
LOG:  statement: COMMIT

'kenji' in der Namenstabelle wurde auf 'tomochi' aktualisiert.

kenji=> select * from names;
  name
---------
 keigo
 tomochi
(2 rows)

Bewegen Sie den Cursor

Ich habe auch das scroll () -Experiment ausprobiert, aber weggelassen, da es keinen Unterschied zu SQL gab, der beachtet werden sollte.

Recommended Posts

Python und DB: DBI-Cursor verstehen
Vollständiges Verständnis von Python-Threading und Multiprocessing
Python selbst verstehen
[Python] Ein grobes Verständnis von Iterablen, Iteratoren und Generatoren
Python- und Numpy-Tipps
[Python] Pip und Wheel
Python Iterator und Generator
Python-Pakete und -Module
Vue-Cli- und Python-Integration
Probieren Sie die DB-Operation mit Python aus und visualisieren Sie sie mit d3
Ruby, Python und Map
LiNGAM (ICA-Version) mit mathematischen Formeln und Python zu verstehen
Python-Eingabe und Ausgabe
Python und Ruby teilen sich
Asynchrone Verarbeitung von Python ~ Asynchron vollständig verstehen und warten ~
Erhalten Sie ein abstraktes Verständnis der Python-Module und -Pakete
Python asyncio und ContextVar
[Einführung in cx_Oracle] (Teil 6) Zuordnung von DB- und Python-Datentypen
Probleme und Lösungen bei der Frage nach MySQL db in Python 3
Programmieren mit Python und Tkinter
Ver- und Entschlüsselung mit Python
Python: Klassen- und Instanzvariablen
3-3, Python-Zeichenfolge und Zeichencode
Python 2-Serie und 3-Serie (Anaconda Edition)
Python und Hardware-Verwenden von RS232C mit Python-
Python auf Ruby und wütend Ruby auf Python
Python Real Number Division (/) und Integer Division (//)
Installieren Sie Python und Flask (Windows 10)
Informationen zu Python-Objekten und -Klassen
Informationen zu Python-Variablen und -Objekten
Apache mod_auth_tkt und Python AuthTkt
Å (Ongustorome) und NFC @ Python
Lernen Sie Python-Pakete und -Module kennen
# 2 [python3] Trennung und Kommentar aus
Flache Python-Kopie und tiefe Kopie
Python und Ruby Slice Memo
Greifen Sie über Python auf Oracle DB zu
Python-Installation und grundlegende Grammatik
Ich habe Java und Python verglichen!
Flache Python-Kopie und tiefe Kopie
Über Python, len () und randint ()
Informationen zu Python-Datums- und Zeitzone
Installieren Sie Python 3.7 und Django 3.0 (CentOS)
Paiza Python Primer 8: Grundlegendes zu Klassen
Python-Umgebungskonstruktion und TensorFlow
Python-Klassen- und Instanzvariablen
Ruby- und Python-Syntax ~ branch ~
[Python] Python und Sicherheit - is Was ist Python?
Stapel und Warteschlange in Python
Python-Metaklasse und SQLalchemie deklarativ
Implementierung von Fibonacci und Primzahlen (Python)
Python-Grundlagen: Bedingungen und Iterationen
Python-Bitoperator und logische Summe
Python-Debug- und Testmodul
Python-Liste und Tapples und Kommas
Python-Variablen und Objekt-IDs
Python-Listeneinschlussnotation und Generator
Über Python und reguläre Ausdrücke