MySQL ist heute eines der beliebtesten Datenbankmanagementsysteme (DBMS) auf dem Markt. Im diesjährigen DB-Engines-Ranking belegte es hinter Oracle DBMS den zweiten Platz. Da die meisten Softwareanwendungen in irgendeiner Form mit Daten interagieren müssen, bieten Programmiersprachen wie Python Tools zum Speichern und Zugreifen auf diese Datenquellen.
Mit den in diesem Tutorial beschriebenen Techniken können Sie eine MySQL-Datenbank effizient in eine Python-Anwendung integrieren. Sie entwickeln eine kleine MySQL-Datenbank für ein Filmbewertungssystem und lernen, wie Sie diese direkt aus Ihrem Python-Code abfragen.
Am Ende dieses Tutorials können Sie:
- Identifizieren Sie einzigartige Merkmale von MySQL
- Verbinden Sie Ihre Anwendung zu einer MySQL-Datenbank
- Fragen Sie die Datenbank ab, um erforderliche Daten abzurufen
- Ausnahmen behandeln die beim Zugriff auf die Datenbank auftreten
- Verwenden Sie Best Practices beim Erstellen von Datenbankanwendungen
Um dieses Tutorial optimal nutzen zu können, sollten Sie über Grundkenntnisse in Python-Konzepten wie for
verfügen Schleifen, Funktionen, Ausnahmebehandlung und Installieren von Python-Paketen mit pip
. Außerdem sollten Sie über ein grundlegendes Verständnis von relationalen Datenbankverwaltungssystemen und SQL-Abfragen wie SELECT
verfügen , DROP
, CREATE
, und JOIN
.
Kostenloser Download: Holen Sie sich ein Beispielkapitel aus Python Tricks:The Book, das Ihnen die Best Practices von Python mit einfachen Beispielen zeigt, die Sie sofort anwenden können, um schöneren + Pythonic-Code zu schreiben.
Vergleich von MySQL mit anderen SQL-Datenbanken
SQL steht für Structured Query Language und ist eine weit verbreitete Programmiersprache zur Verwaltung relationaler Datenbanken. Sie haben vielleicht schon von den verschiedenen Varianten von SQL-basierten DBMSs gehört. Zu den beliebtesten gehören MySQL, PostgreSQL, SQLite und SQL Server. Alle diese Datenbanken sind mit den SQL-Standards konform, jedoch mit unterschiedlichem Grad der Konformität.
Open Source sein Seit seiner Gründung im Jahr 1995 hat sich MySQL schnell zum Marktführer unter den SQL-Lösungen entwickelt. MySQL ist auch Teil des Oracle-Ökosystems. Während die Kernfunktionalität völlig kostenlos ist, gibt es auch einige kostenpflichtige Add-Ons. Derzeit wird MySQL von allen großen Technologieunternehmen verwendet, darunter Google, LinkedIn, Uber, Netflix, Twitter und andere.
Abgesehen von einer großen Open-Source-Community zur Unterstützung gibt es viele andere Gründe für den Erfolg von MySQL:
-
Einfache Installation: MySQL wurde entwickelt, um benutzerfreundlich zu sein. Es ist ziemlich einfach, eine MySQL-Datenbank einzurichten, und mehrere weit verbreitete Tools von Drittanbietern, wie phpMyAdmin, optimieren den Einrichtungsprozess weiter. MySQL ist für alle wichtigen Betriebssysteme verfügbar, einschließlich Windows, macOS, Linux und Solaris.
-
Geschwindigkeit: MySQL hat den Ruf, eine überaus schnelle Datenbanklösung zu sein. Es hat einen relativ geringen Platzbedarf und ist auf lange Sicht extrem skalierbar.
-
Benutzerrechte und Sicherheit: MySQL wird mit einem Skript geliefert, mit dem Sie die Kennwortsicherheitsstufe festlegen, Administratorkennwörter zuweisen und Benutzerkontoberechtigungen hinzufügen und entfernen können. Dieses Skript vereinfacht den Administrationsprozess für ein Webhosting-Benutzerverwaltungsportal. Andere DBMS, wie PostgreSQL, verwenden Konfigurationsdateien, die komplizierter zu verwenden sind.
Während MySQL für seine Geschwindigkeit und Benutzerfreundlichkeit bekannt ist, können Sie mit PostgreSQL erweiterte Funktionen erhalten. Außerdem ist MySQL nicht vollständig SQL-kompatibel und hat bestimmte funktionale Einschränkungen, wie z. B. keine Unterstützung für FULL JOIN
Klauseln.
Möglicherweise treten auch einige Probleme beim gleichzeitigen Lesen und Schreiben in MySQL auf. Wenn viele Benutzer gleichzeitig Daten in Ihre Software schreiben, ist PostgreSQL möglicherweise die bessere Wahl.
Hinweis: Einen eingehenderen Vergleich von MySQL und PostgreSQL in einem realen Kontext finden Sie unter Why Uber Engineering Switched from Postgres to MySQL.
SQL Server ist auch ein sehr beliebtes DBMS und bekannt für seine Zuverlässigkeit, Effizienz und Sicherheit. Es wird von Unternehmen bevorzugt, insbesondere im Bankenbereich, die regelmäßig mit großen Verkehrslasten zu tun haben. Es ist eine kommerzielle Lösung und eines der Systeme, die am besten mit Windows-Diensten kompatibel sind.
Als Oracle 2010 Sun Microsystems und MySQL übernahm, machten sich viele Sorgen um die Zukunft von MySQL. Oracle war damals der größte Konkurrent von MySQL. Entwickler befürchteten, dass dies eine feindliche Übernahme von Oracle mit dem Ziel sei, MySQL zu zerstören.
Mehrere Entwickler unter der Leitung von Michael Widenius, dem ursprünglichen Autor von MySQL, erstellten einen Fork der MySQL-Codebasis und legten den Grundstein für MariaDB. Ziel war es, den Zugriff auf MySQL zu sichern und für immer frei zu halten.
Bis heute bleibt MariaDB vollständig GPL-lizenziert und bleibt somit vollständig gemeinfrei. Einige Funktionen von MySQL hingegen sind nur mit kostenpflichtigen Lizenzen verfügbar. Außerdem bietet MariaDB mehrere äußerst nützliche Funktionen, die vom MySQL-Server nicht unterstützt werden, wie verteiltes SQL und spaltenweise Speicherung. Weitere Unterschiede zwischen MySQL und MariaDB finden Sie auf der Website von MariaDB.
MySQL verwendet eine sehr ähnliche Syntax wie Standard-SQL. Es gibt jedoch einige bemerkenswerte Unterschiede, die in der offiziellen Dokumentation erwähnt werden.
Installieren von MySQL Server und MySQL Connector/Python
Um nun mit der Arbeit an diesem Tutorial zu beginnen, müssen Sie zwei Dinge einrichten:einen MySQL-Server und einen MySQL-Connector . Der MySQL-Server stellt alle Dienste bereit, die für die Handhabung Ihrer Datenbank erforderlich sind. Sobald der Server betriebsbereit ist, können Sie Ihre Python-Anwendung über MySQL Connector/Python damit verbinden.
MySQL-Server installieren
Die offizielle Dokumentation beschreibt die empfohlene Vorgehensweise zum Herunterladen und Installieren des MySQL-Servers. Sie finden Anleitungen für alle gängigen Betriebssysteme, darunter Windows, macOS, Solaris, Linux und viele mehr.
Für Windows ist es am besten, den MySQL Installer herunterzuladen und ihn den gesamten Prozess erledigen zu lassen. Der Installationsmanager unterstützt Sie auch bei der Konfiguration der Sicherheitseinstellungen des MySQL-Servers. Auf der Seite "Konten und Rollen" müssen Sie ein Passwort für root eingeben (admin)-Konto und fügen Sie optional auch andere Benutzer mit unterschiedlichen Berechtigungen hinzu:
Während Sie während der Einrichtung Anmeldeinformationen für das Root-Konto angeben müssen, können Sie diese Einstellungen später ändern.
Hinweis: Merken Sie sich den Hostnamen, den Benutzernamen und das Passwort, da diese später benötigt werden, um eine Verbindung mit dem MySQL-Server herzustellen.
Obwohl Sie für dieses Tutorial nur den MySQL-Server benötigen, können Sie mit diesen Installationsprogrammen auch andere hilfreiche Tools wie MySQL Workbench einrichten. Wenn Sie MySQL nicht direkt in Ihrem Betriebssystem installieren möchten, ist die Bereitstellung von MySQL unter Linux mit Docker eine bequeme Alternative.
Installieren von MySQL Connector/Python
Ein Datenbanktreiber ist eine Software, die es einer Anwendung ermöglicht, sich mit einem Datenbanksystem zu verbinden und mit ihm zu interagieren. Programmiersprachen wie Python benötigen einen speziellen Treiber, bevor sie mit einer Datenbank eines bestimmten Anbieters kommunizieren können.
Diese Treiber werden normalerweise als Module von Drittanbietern bezogen. Die Python-Datenbank-API (DB-API) definiert die Standardschnittstelle, der alle Python-Datenbanktreiber entsprechen müssen. Diese Details sind in PEP 249 dokumentiert. Alle Python-Datenbanktreiber wie sqlite3 für SQLite, psycopg für PostgreSQL und MySQL Connector/Python für MySQL befolgen diese Implementierungsregeln.
Hinweis: In der offiziellen Dokumentation von MySQL wird der Begriff Connector verwendet statt Treiber . Technisch gesehen sind Konnektoren nur mit der Verbindung zu einer Datenbank verbunden, nicht mit der Interaktion. Der Begriff wird jedoch häufig für das gesamte Datenbankzugriffsmodul verwendet, das aus den Konnektoren und besteht der Fahrer.
Um die Konsistenz mit der Dokumentation zu wahren, sehen Sie den Begriff Connector wann immer MySQL erwähnt wird.
Viele gängige Programmiersprachen haben ihre eigene Datenbank-API. Beispielsweise verfügt Java über die Java Database Connectivity (JDBC) API. Wenn Sie eine Java-Anwendung mit einer MySQL-Datenbank verbinden müssen, müssen Sie den MySQL-JDBC-Connector verwenden, der der JDBC-API folgt.
In ähnlicher Weise müssen Sie in Python einen Python-MySQL-Connector installieren, um mit einer MySQL-Datenbank zu interagieren. Viele Pakete folgen den DB-API-Standards, aber das beliebteste unter ihnen ist MySQL Connector/Python. Sie können es mit pip
abrufen :
$ pip install mysql-connector-python
pip
installiert den Connector als Drittanbietermodul in der aktuell aktiven virtuellen Umgebung. Es wird empfohlen, dass Sie eine isolierte virtuelle Umgebung für das Projekt zusammen mit allen Abhängigkeiten einrichten.
Um zu testen, ob die Installation erfolgreich war, geben Sie den folgenden Befehl auf Ihrem Python-Terminal ein:
>>>>>> import mysql.connector
Wenn der obige Code ohne Fehler ausgeführt wird, dann mysql.connector
ist installiert und einsatzbereit. Wenn Sie auf Fehler stoßen, vergewissern Sie sich, dass Sie sich in der richtigen virtuellen Umgebung befinden und den richtigen Python-Interpreter verwenden.
Stellen Sie sicher, dass Sie den richtigen mysql-connector-python
installieren -Paket, das eine reine Python-Implementierung ist. Hüten Sie sich vor ähnlich benannten, aber inzwischen veralteten Konnektoren wie mysql-connector
.
Herstellen einer Verbindung mit MySQL Server
MySQL ist serverbasiert Datenbankverwaltungssystem. Ein Server kann mehrere Datenbanken enthalten. Um mit einer Datenbank zu interagieren, müssen Sie zuerst eine Verbindung mit dem Server herstellen. Der allgemeine Arbeitsablauf eines Python-Programms, das mit einer MySQL-basierten Datenbank interagiert, ist wie folgt:
- Verbinden Sie sich mit dem MySQL-Server.
- Erstellen Sie eine neue Datenbank.
- Mit der neu erstellten oder einer bestehenden Datenbank verbinden.
- Führen Sie eine SQL-Abfrage aus und rufen Sie Ergebnisse ab.
- Informiere die Datenbank, wenn Änderungen an einer Tabelle vorgenommen werden.
- Schließen Sie die Verbindung zum MySQL-Server.
Dies ist ein allgemeiner Arbeitsablauf, der je nach Anwendung variieren kann. Aber was auch immer die Anwendung sein mag, der erste Schritt besteht darin, Ihre Datenbank mit Ihrer Anwendung zu verbinden.
Herstellen einer Verbindung
Der erste Schritt bei der Interaktion mit einem MySQL-Server besteht darin, eine Verbindung herzustellen. Dazu benötigen Sie connect()
aus dem mysql.connector
Modul. Diese Funktion übernimmt Parameter wie host
, user
, und password
und gibt eine MySQLConnection
zurück Objekt. Sie können diese Anmeldeinformationen als Eingabe vom Benutzer erhalten und an connect()
übergeben :
from getpass import getpass
from mysql.connector import connect, Error
try:
with connect(
host="localhost",
user=input("Enter username: "),
password=getpass("Enter password: "),
) as connection:
print(connection)
except Error as e:
print(e)
Der obige Code verwendet die eingegebenen Anmeldeinformationen, um eine Verbindung mit Ihrem MySQL-Server herzustellen. Im Gegenzug erhalten Sie eine MySQLConnection
Objekt, das in connection
gespeichert wird Variable. Von nun an verwenden Sie diese Variable, um auf Ihren MySQL-Server zuzugreifen.
Im obigen Code sind mehrere wichtige Dinge zu beachten:
-
Sie sollten sich immer mit den Ausnahmen befassen, die beim Herstellen einer Verbindung zum MySQL-Server auftreten können. Aus diesem Grund verwenden Sie einen
try
…except
blockieren, um eventuell auftretende Ausnahmen abzufangen und auszugeben. -
Sie sollten die Verbindung immer schließen, nachdem Sie mit dem Zugriff auf die Datenbank fertig sind. Unbenutzte Verbindungen offen zu lassen, kann zu mehreren unerwarteten Fehlern und Leistungsproblemen führen. Der obige Code nutzt einen Kontextmanager, der
with
verwendet , wodurch der Verbindungsbereinigungsprozess abstrahiert wird. -
Sie sollten Ihre Anmeldedaten niemals fest codieren , also Ihren Benutzernamen und Ihr Passwort, direkt in einem Python-Skript. Dies ist eine schlechte Methode für die Bereitstellung und stellt eine ernsthafte Sicherheitsbedrohung dar. Der obige Code fordert den Benutzer zur Eingabe von Anmeldeinformationen auf. Es verwendet das eingebaute
getpass
Modul, um das Passwort zu verbergen. Dies ist zwar besser als Hartcodierung, aber es gibt andere, sicherere Möglichkeiten, vertrauliche Informationen zu speichern, z. B. die Verwendung von Umgebungsvariablen.
Sie haben jetzt eine Verbindung zwischen Ihrem Programm und Ihrem MySQL-Server hergestellt, aber Sie müssen noch entweder eine neue Datenbank erstellen oder sich mit einer bestehenden Datenbank innerhalb des Servers verbinden.
Erstellen einer neuen Datenbank
Im letzten Abschnitt haben Sie eine Verbindung zu Ihrem MySQL-Server hergestellt. Um eine neue Datenbank zu erstellen, müssen Sie eine SQL-Anweisung ausführen:
CREATE DATABASE books_db;
Die obige Anweisung erstellt eine neue Datenbank mit dem Namen books_db
.
Hinweis: In MySQL muss ein Semikolon (;
) am Ende einer Anweisung, die die Beendigung einer Abfrage bezeichnet. MySQL Connector/Python fügt jedoch automatisch ein Semikolon an das Ende Ihrer Abfragen an, sodass Sie es nicht in Ihrem Python-Code verwenden müssen.
Um eine SQL-Abfrage in Python auszuführen, müssen Sie einen Cursor verwenden, der den Zugriff auf Datenbankeinträge abstrahiert. MySQL Connector/Python stellt Ihnen den MySQLCursor
zur Verfügung -Klasse, die Objekte instanziiert, die MySQL-Abfragen in Python ausführen können. Eine Instanz von MySQLCursor
Klasse wird auch als cursor
bezeichnet .
cursor
Objekte verwenden eine MySQLConnection
Objekt, um mit Ihrem MySQL-Server zu interagieren. So erstellen Sie einen cursor
, verwenden Sie .cursor()
Methode Ihrer connection
Variable:
cursor = connection.cursor()
Der obige Code gibt Ihnen eine Instanz des MySQLCursor
Klasse.
Eine auszuführende Abfrage wird an cursor.execute()
gesendet im Stringformat. In diesem speziellen Fall senden Sie den CREATE DATABASE
Abfrage an cursor.execute()
:
from getpass import getpass
from mysql.connector import connect, Error
try:
with connect(
host="localhost",
user=input("Enter username: "),
password=getpass("Enter password: "),
) as connection:
create_db_query = "CREATE DATABASE online_movie_rating"
with connection.cursor() as cursor:
cursor.execute(create_db_query)
except Error as e:
print(e)
Nachdem Sie den obigen Code ausgeführt haben, haben Sie eine neue Datenbank namens online_movie_rating
auf Ihrem MySQL-Server.
Die CREATE DATABASE
query wird als String in create_db_query
gespeichert Variable und dann an cursor.execute()
übergeben zur Ausführung. Der Code verwendet einen Kontextmanager mit dem cursor
Objekt, um den Bereinigungsprozess durchzuführen.
Möglicherweise erhalten Sie hier eine Fehlermeldung, wenn auf Ihrem Server bereits eine Datenbank mit demselben Namen vorhanden ist. Um dies zu bestätigen, können Sie sich die Namen aller Datenbanken auf Ihrem Server anzeigen lassen. Verwenden derselben MySQLConnection
Objekt von früher, führen Sie SHOW DATABASES
aus Aussage:
>>> show_db_query = "SHOW DATABASES"
>>> with connection.cursor() as cursor:
... cursor.execute(show_db_query)
... for db in cursor:
... print(db)
...
('information_schema',)
('mysql',)
('online_movie_rating',)
('performance_schema',)
('sys',)
Der obige Code gibt die Namen aller Datenbanken aus, die sich derzeit auf Ihrem MySQL-Server befinden. Die SHOW DATABASES
Der Befehl gibt auch einige Datenbanken aus, die Sie nicht auf Ihrem Server erstellt haben, wie information_schema
, performance_schema
, und so weiter. Diese Datenbanken werden automatisch vom MySQL-Server generiert und bieten Zugriff auf eine Vielzahl von Datenbankmetadaten und MySQL-Servereinstellungen.
Sie haben in diesem Abschnitt eine neue Datenbank erstellt, indem Sie CREATE DATABASE
ausgeführt haben Erklärung. Im nächsten Abschnitt erfahren Sie, wie Sie eine Verbindung zu einer bereits vorhandenen Datenbank herstellen.
Verbindung zu einer bestehenden Datenbank herstellen
Im letzten Abschnitt haben Sie eine neue Datenbank namens online_movie_rating
erstellt . Sie haben sich jedoch noch nicht damit verbunden. In vielen Situationen haben Sie bereits eine MySQL-Datenbank, die Sie mit Ihrer Python-Anwendung verbinden möchten.
Sie können dies mit demselben connect()
tun Funktion, die Sie zuvor verwendet haben, indem Sie einen zusätzlichen Parameter namens database
senden :
from getpass import getpass
from mysql.connector import connect, Error
try:
with connect(
host="localhost",
user=input("Enter username: "),
password=getpass("Enter password: "),
database="online_movie_rating",
) as connection:
print(connection)
except Error as e:
print(e)
Der obige Code ist dem zuvor verwendeten Verbindungsskript sehr ähnlich. Die einzige Änderung hier ist eine zusätzliche database
Parameter, wo der Name Ihrer Datenbank an connect()
übergeben wird . Sobald Sie dieses Skript ausführen, werden Sie mit online_movie_rating
verbunden Datenbank.
Erstellen, Ändern und Löschen einer Tabelle
In diesem Abschnitt erfahren Sie, wie Sie einige grundlegende DDL-Abfragen wie CREATE
ausführen , DROP
, und ALTER
mit Python. Sie erhalten einen kurzen Blick auf die MySQL-Datenbank, die Sie im Rest dieses Tutorials verwenden werden. Außerdem erstellen Sie alle für die Datenbank erforderlichen Tabellen und erfahren, wie Sie später Änderungen an diesen Tabellen vornehmen können.
Definieren des Datenbankschemas
Sie können damit beginnen, ein Datenbankschema für ein Online-Filmbewertungssystem zu erstellen. Die Datenbank besteht aus drei Tabellen:
movies
enthält allgemeine Informationen über Filme und hat die folgenden Attribute:id
title
release_year
genre
collection_in_mil
reviewers
enthält Informationen über Personen, die Rezensionen oder Bewertungen gepostet haben, und hat die folgenden Attribute:id
first_name
last_name
ratings
enthält Informationen zu abgegebenen Bewertungen und hat folgende Attribute:movie_id
(Fremdschlüssel)reviewer_id
(Fremdschlüssel)rating
Ein reales Filmbewertungssystem wie IMDb müsste eine Reihe anderer Attribute speichern, wie E-Mails, Filmbesetzungslisten und so weiter. Wenn Sie möchten, können Sie dieser Datenbank weitere Tabellen und Attribute hinzufügen. Aber diese drei Tabellen werden für den Zweck dieses Tutorials ausreichen.
Das folgende Bild zeigt das Datenbankschema:
Die Tabellen in dieser Datenbank stehen in Beziehung zueinander. movies
und reviewers
wird ein viele-zu-viele haben Beziehung, da ein Film von mehreren Rezensenten rezensiert werden kann und ein Rezensent mehrere Filme rezensieren kann. Die ratings
Tabelle verbindet die movies
Tabelle mit den reviewers
Tabelle.
Erstellen von Tabellen mit CREATE TABLE
Aussage
Um nun eine neue Tabelle in MySQL zu erstellen, müssen Sie CREATE TABLE
verwenden Erklärung. Die folgende MySQL-Abfrage erstellt die movies
Tabelle für Ihre online_movie_rating
Datenbank:
CREATE TABLE movies(
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100),
release_year YEAR(4),
genre VARCHAR(100),
collection_in_mil INT
);
Wenn Sie sich schon einmal mit SQL-Anweisungen befasst haben, sind die meisten der obigen Abfragen möglicherweise sinnvoll. Aber es gibt einige Unterschiede in der MySQL-Syntax, die Sie beachten sollten.
Zum Beispiel hat MySQL eine Vielzahl von Datentypen für Sie, einschließlich YEAR
, INT
, BIGINT
, und so weiter. Außerdem verwendet MySQL den AUTO_INCREMENT
Schlüsselwort, wenn ein Spaltenwert beim Einfügen neuer Datensätze automatisch erhöht werden soll.
Um eine neue Tabelle zu erstellen, müssen Sie diese Abfrage an cursor.execute()
übergeben , das eine MySQL-Abfrage akzeptiert und die Abfrage auf der verbundenen MySQL-Datenbank ausführt:
create_movies_table_query = """
CREATE TABLE movies(
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100),
release_year YEAR(4),
genre VARCHAR(100),
collection_in_mil INT
)
"""
with connection.cursor() as cursor:
cursor.execute(create_movies_table_query)
connection.commit()
Jetzt haben Sie die movies
Tabelle in Ihrer Datenbank. Sie übergeben create_movies_table_query
zu cursor.execute()
, das die erforderliche Ausführung durchführt.
Hinweis: Die connection
Variable bezieht sich auf die MySQLConnection
Objekt, das zurückgegeben wurde, als Sie sich mit Ihrer Datenbank verbunden haben.
Beachten Sie auch connection.commit()
Anweisung am Ende des Codes. Standardmäßig führt Ihr MySQL-Connector keine Autocommit-Transaktionen durch. In MySQL treten Änderungen, die in einer Transaktion erwähnt werden, nur auf, wenn Sie ein COMMIT
verwenden Befehl am Ende. Rufen Sie diese Methode immer nach jeder Transaktion auf, um Änderungen in der aktuellen Tabelle vorzunehmen.
So wie bei den movies
führen Sie das folgende Skript aus, um die reviewers
zu erstellen Tabelle:
create_reviewers_table_query = """
CREATE TABLE reviewers (
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100)
)
"""
with connection.cursor() as cursor:
cursor.execute(create_reviewers_table_query)
connection.commit()
Bei Bedarf können Sie weitere Informationen über einen Bewerter hinzufügen, z. B. seine E-Mail-ID oder demografische Informationen. Aber first_name
und last_name
wird vorerst deinen Zweck erfüllen.
Abschließend können Sie die ratings
erstellen Tabelle mit dem folgenden Skript:
create_ratings_table_query = """
CREATE TABLE ratings (
movie_id INT,
reviewer_id INT,
rating DECIMAL(2,1),
FOREIGN KEY(movie_id) REFERENCES movies(id),
FOREIGN KEY(reviewer_id) REFERENCES reviewers(id),
PRIMARY KEY(movie_id, reviewer_id)
)
"""
with connection.cursor() as cursor:
cursor.execute(create_ratings_table_query)
connection.commit()
Die Implementierung von Fremdschlüsselbeziehungen in MySQL ist im Vergleich zum Standard-SQL etwas anders und eingeschränkt. In MySQL müssen sowohl das übergeordnete als auch das untergeordnete Element in der Fremdschlüsseleinschränkung dieselbe Speicher-Engine verwenden .
Eine Speicher-Engine ist die zugrunde liegende Softwarekomponente, die ein Datenbankverwaltungssystem zum Ausführen von SQL-Operationen verwendet. In MySQL gibt es Speicher-Engines in zwei verschiedenen Varianten:
-
Transaktionsspeicher-Engines sind transaktionssicher und ermöglichen es Ihnen, Transaktionen mit einfachen Befehlen wie
rollback
rückgängig zu machen . Viele beliebte MySQL-Engines, einschließlich InnoDB und NDB, gehören zu dieser Kategorie. -
Nicht-transaktionale Speicher-Engines sind auf aufwendigen manuellen Code angewiesen, um in einer Datenbank festgeschriebene Anweisungen rückgängig zu machen. MyISAM, MEMORY und viele andere MySQL-Engines sind nicht transaktional.
InnoDB ist die standardmäßige und beliebteste Speicher-Engine. Es hilft, die Datenintegrität aufrechtzuerhalten, indem es Fremdschlüsselbeschränkungen unterstützt. Das bedeutet, dass jede CRUD-Operation auf einem Fremdschlüssel überprüft wird, um sicherzustellen, dass sie nicht zu Inkonsistenzen zwischen verschiedenen Tabellen führt.
Beachten Sie auch, dass die ratings
Tabelle verwendet die Spalten movie_id
und reviewer_id
, beides Fremdschlüssel, gemeinsam als Primärschlüssel . Dieser Schritt stellt sicher, dass ein Rezensent denselben Film nicht zweimal bewerten kann.
Sie können denselben Cursor für mehrere Ausführungen wiederverwenden. In diesem Fall würden alle Ausführungen zu einer atomaren Transaktion statt zu mehreren separaten Transaktionen. Beispielsweise können Sie alle CREATE TABLE
ausführen Anweisungen mit einem Cursor und übertragen Sie Ihre Transaktion dann nur einmal:
with connection.cursor() as cursor:
cursor.execute(create_movies_table_query)
cursor.execute(create_reviewers_table_query)
cursor.execute(create_ratings_table_query)
connection.commit()
Der obige Code führt zuerst alle drei CREATE
aus Aussagen. Dann wird ein COMMIT
gesendet Befehl an den MySQL-Server, der Ihre Transaktion festschreibt. Sie können auch .rollback()
verwenden um ein ROLLBACK
zu senden Befehl an den MySQL-Server und entfernen Sie alle Datenänderungen aus der Transaktion.
Anzeigen eines Tabellenschemas mit DESCRIBE
Aussage
Nachdem Sie nun alle drei Tabellen erstellt haben, können Sie sich ihr Schema mit der folgenden SQL-Anweisung ansehen:
DESCRIBE <table_name>;
Um einige Ergebnisse vom cursor
zurück zu bekommen Objekt, müssen Sie cursor.fetchall()
verwenden . Diese Methode ruft alle Zeilen der zuletzt ausgeführten Anweisung ab. Angenommen, Sie haben bereits die MySQLConnection
Objekt in der connection
Variable können Sie alle von cursor.fetchall()
abgerufenen Ergebnisse ausdrucken :
>>> show_table_query = "DESCRIBE movies"
>>> with connection.cursor() as cursor:
... cursor.execute(show_table_query)
... # Fetch rows from last executed query
... result = cursor.fetchall()
... for row in result:
... print(row)
...
('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')
('title', 'varchar(100)', 'YES', '', None, '')
('release_year', 'year(4)', 'YES', '', None, '')
('genre', 'varchar(100)', 'YES', '', None, '')
('collection_in_mil', 'int(11)', 'YES', '', None, '')
Nachdem Sie den obigen Code ausgeführt haben, sollten Sie eine Tabelle mit Informationen zu allen Spalten in movies
erhalten Tisch. Für jede Spalte erhalten Sie Details wie den Datentyp der Spalte, ob die Spalte ein Primärschlüssel ist usw.
Ändern eines Tabellenschemas mit ALTER
Aussage
In den movies
Tabelle haben Sie eine Spalte namens collection_in_mil
, die die Kassensammlung eines Films in Millionen von Dollar enthält. Sie können die folgende MySQL-Anweisung schreiben, um den Datentyp von collection_in_mil
zu ändern Attribut von INT
zu DECIMAL
:
ALTER TABLE movies MODIFY COLUMN collection_in_mil DECIMAL(4,1);
DECIMAL(4,1)
bedeutet eine Dezimalzahl, die maximal 4
haben kann Ziffern, davon 1
ist dezimal, z. B. 120.1
, 3.4
, 38.0
, und so weiter. Nach dem Ausführen von ALTER TABLE
-Anweisung können Sie das aktualisierte Tabellenschema mit DESCRIBE
anzeigen :
>>> alter_table_query = """
... ALTER TABLE movies
... MODIFY COLUMN collection_in_mil DECIMAL(4,1)
... """
>>> show_table_query = "DESCRIBE movies"
>>> with connection.cursor() as cursor:
... cursor.execute(alter_table_query)
... cursor.execute(show_table_query)
... # Fetch rows from last executed query
... result = cursor.fetchall()
... print("Movie Table Schema after alteration:")
... for row in result:
... print(row)
...
Movie Table Schema after alteration
('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')
('title', 'varchar(100)', 'YES', '', None, '')
('release_year', 'year(4)', 'YES', '', None, '')
('genre', 'varchar(100)', 'YES', '', None, '')
('collection_in_mil', 'decimal(4,1)', 'YES', '', None, '')
Wie in der Ausgabe gezeigt, die collection_in_mil
Attribut ist jetzt vom Typ DECIMAL(4,1)
. Beachten Sie auch, dass Sie im obigen Code cursor.execute()
aufrufen zweimal. Aber cursor.fetchall()
ruft Zeilen nur von der zuletzt ausgeführten Abfrage ab, die show_table_query
ist .
Löschen von Tabellen mit DROP
Aussage
Um eine Tabelle zu löschen, müssen Sie DROP TABLE
ausführen Anweisung in MySQL. Das Löschen einer Tabelle ist irreversibel Prozess. Wenn Sie den folgenden Code ausführen, müssen Sie CREATE TABLE
aufrufen erneut abfragen, um die ratings
zu verwenden Tabelle in den nächsten Abschnitten.
Um die ratings
zu löschen Tabelle, senden Sie drop_table_query
zu cursor.execute()
:
drop_table_query = "DROP TABLE ratings"
with connection.cursor() as cursor:
cursor.execute(drop_table_query)
Wenn Sie den obigen Code ausführen, haben Sie die ratings
erfolgreich gelöscht Tabelle.
Datensätze in Tabellen einfügen
Im letzten Abschnitt haben Sie drei Tabellen in Ihrer Datenbank erstellt:movies
, reviewers
und ratings
. Jetzt müssen Sie diese Tabellen mit Daten füllen. Dieser Abschnitt behandelt zwei verschiedene Möglichkeiten zum Einfügen von Datensätzen in den MySQL Connector für Python.
Die erste Methode, .execute()
, funktioniert gut, wenn die Anzahl der Datensätze klein ist und die Datensätze fest codiert werden können. Die zweite Methode, .executemany()
, ist beliebter und eignet sich besser für reale Szenarien.
Mit .execute()
Der erste Ansatz verwendet dasselbe cursor.execute()
Methode, die Sie bisher verwendet haben. Sie schreiben den INSERT INTO
Abfrage in einer Zeichenfolge und übergeben Sie sie an cursor.execute()
. Mit dieser Methode können Sie Daten in die movies
einfügen Tabelle.
Als Referenz die movies
Tabelle hat fünf Attribute:
id
title
release_year
genre
collection_in_mil
Sie müssen keine Daten für id
hinzufügen als AUTO_INCREMENT
berechnet automatisch id
für dich. Das folgende Skript fügt Datensätze in die movies
ein Tabelle:
insert_movies_query = """
INSERT INTO movies (title, release_year, genre, collection_in_mil)
VALUES
("Forrest Gump", 1994, "Drama", 330.2),
("3 Idiots", 2009, "Drama", 2.4),
("Eternal Sunshine of the Spotless Mind", 2004, "Drama", 34.5),
("Good Will Hunting", 1997, "Drama", 138.1),
("Skyfall", 2012, "Action", 304.6),
("Gladiator", 2000, "Action", 188.7),
("Black", 2005, "Drama", 3.0),
("Titanic", 1997, "Romance", 659.2),
("The Shawshank Redemption", 1994, "Drama",28.4),
("Udaan", 2010, "Drama", 1.5),
("Home Alone", 1990, "Comedy", 286.9),
("Casablanca", 1942, "Romance", 1.0),
("Avengers: Endgame", 2019, "Action", 858.8),
("Night of the Living Dead", 1968, "Horror", 2.5),
("The Godfather", 1972, "Crime", 135.6),
("Haider", 2014, "Action", 4.2),
("Inception", 2010, "Adventure", 293.7),
("Evil", 2003, "Horror", 1.3),
("Toy Story 4", 2019, "Animation", 434.9),
("Air Force One", 1997, "Drama", 138.1),
("The Dark Knight", 2008, "Action",535.4),
("Bhaag Milkha Bhaag", 2013, "Sport", 4.1),
("The Lion King", 1994, "Animation", 423.6),
("Pulp Fiction", 1994, "Crime", 108.8),
("Kai Po Che", 2013, "Sport", 6.0),
("Beasts of No Nation", 2015, "War", 1.4),
("Andadhun", 2018, "Thriller", 2.9),
("The Silence of the Lambs", 1991, "Crime", 68.2),
("Deadpool", 2016, "Action", 363.6),
("Drishyam", 2015, "Mystery", 3.0)
"""
with connection.cursor() as cursor:
cursor.execute(insert_movies_query)
connection.commit()
The movies
table is now loaded with thirty records. The code calls connection.commit()
at the end. It’s crucial to call .commit()
after preforming any modifications to a table.
Using .executemany()
The previous approach is more suitable when the number of records is fairly small and you can write these records directly into the code. But this is rarely true. You’ll often have this data stored in some other file, or the data will be generated by a different script and will need to be added to the MySQL database.
This is where .executemany()
comes in handy. It accepts two parameters:
- A query that contains placeholders for the records that need to be inserted
- A list that contains all records that you wish to insert
The following example inserts records for the reviewers
Tabelle:
insert_reviewers_query = """
INSERT INTO reviewers
(first_name, last_name)
VALUES ( %s, %s )
"""
reviewers_records = [
("Chaitanya", "Baweja"),
("Mary", "Cooper"),
("John", "Wayne"),
("Thomas", "Stoneman"),
("Penny", "Hofstadter"),
("Mitchell", "Marsh"),
("Wyatt", "Skaggs"),
("Andre", "Veiga"),
("Sheldon", "Cooper"),
("Kimbra", "Masters"),
("Kat", "Dennings"),
("Bruce", "Wayne"),
("Domingo", "Cortes"),
("Rajesh", "Koothrappali"),
("Ben", "Glocker"),
("Mahinder", "Dhoni"),
("Akbar", "Khan"),
("Howard", "Wolowitz"),
("Pinkie", "Petit"),
("Gurkaran", "Singh"),
("Amy", "Farah Fowler"),
("Marlon", "Crafford"),
]
with connection.cursor() as cursor:
cursor.executemany(insert_reviewers_query, reviewers_records)
connection.commit()
In the script above, you pass both the query and the list of records as arguments to .executemany()
. These records could have been fetched from a file or from the user and stored in the reviewers_records
Liste.
The code uses %s
as a placeholder for the two strings that had to be inserted in the insert_reviewers_query
. Placeholders act as format specifiers and help reserve a spot for a variable inside a string. The specified variable is then added to this spot during execution.
You can similarly use .executemany()
to insert records in the ratings
Tabelle:
insert_ratings_query = """
INSERT INTO ratings
(rating, movie_id, reviewer_id)
VALUES ( %s, %s, %s)
"""
ratings_records = [
(6.4, 17, 5), (5.6, 19, 1), (6.3, 22, 14), (5.1, 21, 17),
(5.0, 5, 5), (6.5, 21, 5), (8.5, 30, 13), (9.7, 6, 4),
(8.5, 24, 12), (9.9, 14, 9), (8.7, 26, 14), (9.9, 6, 10),
(5.1, 30, 6), (5.4, 18, 16), (6.2, 6, 20), (7.3, 21, 19),
(8.1, 17, 18), (5.0, 7, 2), (9.8, 23, 3), (8.0, 22, 9),
(8.5, 11, 13), (5.0, 5, 11), (5.7, 8, 2), (7.6, 25, 19),
(5.2, 18, 15), (9.7, 13, 3), (5.8, 18, 8), (5.8, 30, 15),
(8.4, 21, 18), (6.2, 23, 16), (7.0, 10, 18), (9.5, 30, 20),
(8.9, 3, 19), (6.4, 12, 2), (7.8, 12, 22), (9.9, 15, 13),
(7.5, 20, 17), (9.0, 25, 6), (8.5, 23, 2), (5.3, 30, 17),
(6.4, 5, 10), (8.1, 5, 21), (5.7, 22, 1), (6.3, 28, 4),
(9.8, 13, 1)
]
with connection.cursor() as cursor:
cursor.executemany(insert_ratings_query, ratings_records)
connection.commit()
All three tables are now populated with data. You now have a fully functional online movie rating database. The next step is to understand how to interact with this database.
Reading Records From the Database
Until now, you’ve been building your database. Now it’s time to perform some queries on it and find some interesting properties from this dataset. In this section, you’ll learn how to read records from database tables using the SELECT
Aussage.
Reading Records Using the SELECT
Statement
To retrieve records, you need to send a SELECT
query to cursor.execute()
. Then you use cursor.fetchall()
to extract the retrieved table in the form of a list of rows or records.
Try writing a MySQL query to select all records from the movies
table and send it to .execute()
:
>>> select_movies_query = "SELECT * FROM movies LIMIT 5"
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... result = cursor.fetchall()
... for row in result:
... print(row)
...
(1, 'Forrest Gump', 1994, 'Drama', Decimal('330.2'))
(2, '3 Idiots', 2009, 'Drama', Decimal('2.4'))
(3, 'Eternal Sunshine of the Spotless Mind', 2004, 'Drama', Decimal('34.5'))
(4, 'Good Will Hunting', 1997, 'Drama', Decimal('138.1'))
(5, 'Skyfall', 2012, 'Action', Decimal('304.6'))
The result
variable holds the records returned from using .fetchall()
. It’s a list of tuples representing individual records from the table.
In the query above, you use the LIMIT
clause to constrain the number of rows that are received from the SELECT
Erklärung. Developers often use LIMIT
to perform pagination when handling large volumes of data.
In MySQL, the LIMIT
clause takes one or two nonnegative numeric arguments. When using one argument, you specify the maximum number of rows to return. Since your query includes LIMIT 5
, only the first 5
records are fetched. When using both arguments, you can also specify the offset of the first row to return:
SELECT * FROM movies LIMIT 2,5;
The first argument specifies an offset of 2
, and the second argument constrains the number of returned rows to 5
. The above query will return rows 3 to 7.
You can also query for selected columns:
>>>>>> select_movies_query = "SELECT title, release_year FROM movies LIMIT 5"
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... for row in cursor.fetchall():
... print(row)
...
('Forrest Gump', 1994)
('3 Idiots', 2009)
('Eternal Sunshine of the Spotless Mind', 2004)
('Good Will Hunting', 1997)
('Skyfall', 2012)
Now, the code outputs values only from the two specified columns:title
and release_year
.
Filtering Results Using the WHERE
Clause
You can filter table records by specific criteria using the WHERE
Klausel. For example, to retrieve all movies with a box office collection greater than $300 million, you could run the following query:
SELECT title, collection_in_mil
FROM movies
WHERE collection_in_mil > 300;
You can also use ORDER BY
clause in the last query to sort the results from the highest to the lowest earner:
>>> select_movies_query = """
... SELECT title, collection_in_mil
... FROM movies
... WHERE collection_in_mil > 300
... ORDER BY collection_in_mil DESC
... """
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... for movie in cursor.fetchall():
... print(movie)
...
('Avengers: Endgame', Decimal('858.8'))
('Titanic', Decimal('659.2'))
('The Dark Knight', Decimal('535.4'))
('Toy Story 4', Decimal('434.9'))
('The Lion King', Decimal('423.6'))
('Deadpool', Decimal('363.6'))
('Forrest Gump', Decimal('330.2'))
('Skyfall', Decimal('304.6'))
MySQL offers a plethora of string formatting operations like CONCAT
for concatenating strings. Often, websites will show the movie title along with its release year to avoid confusion. To retrieve the titles of the top five grossing movies, concatenated with their release years, you can write the following query:
>>> select_movies_query = """
... SELECT CONCAT(title, " (", release_year, ")"),
... collection_in_mil
... FROM movies
... ORDER BY collection_in_mil DESC
... LIMIT 5
... """
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... for movie in cursor.fetchall():
... print(movie)
...
('Avengers: Endgame (2019)', Decimal('858.8'))
('Titanic (1997)', Decimal('659.2'))
('The Dark Knight (2008)', Decimal('535.4'))
('Toy Story 4 (2019)', Decimal('434.9'))
('The Lion King (1994)', Decimal('423.6'))
If you don’t want to use the LIMIT
clause and you don’t need to fetch all the records, then the cursor
object has .fetchone()
and .fetchmany()
methods as well:
.fetchone()
retrieves either the next row of the result, as a tuple, orNone
if no more rows are available..fetchmany()
retrieves the next set of rows from the result as a list of tuples. It has asize
argument, which defaults to1
, that you can use to specify the number of rows you need to fetch. If no more rows are available, then the method returns an empty list.
Try retrieving the titles of the five highest-grossing movies concatenated with their release years again, but this time use .fetchmany()
:
>>> select_movies_query = """
... SELECT CONCAT(title, " (", release_year, ")"),
... collection_in_mil
... FROM movies
... ORDER BY collection_in_mil DESC
... """
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... for movie in cursor.fetchmany(size=5):
... print(movie)
... cursor.fetchall()
...
('Avengers: Endgame (2019)', Decimal('858.8'))
('Titanic (1997)', Decimal('659.2'))
('The Dark Knight (2008)', Decimal('535.4'))
('Toy Story 4 (2019)', Decimal('434.9'))
('The Lion King (1994)', Decimal('423.6'))
The output with .fetchmany()
is similar to what you received when you used the LIMIT
Klausel. You might have noticed the additional cursor.fetchall()
call at the end. You do this to clean all the remaining results that weren’t read by .fetchmany()
.
It’s necessary to clean all unread results before executing any other statements on the same connection. Otherwise, an InternalError: Unread result found
exception will be raised.
Handling Multiple Tables Using the JOIN
Statement
If you found the queries in the last section to be quite straightforward, don’t worry. You can make your SELECT
queries as complex as you want using the same methods from the last section.
Let’s look at some slightly more complex JOIN
queries. If you want to find out the name of the top five highest-rated movies in your database, then you can run the following query:
>>> select_movies_query = """
... SELECT title, AVG(rating) as average_rating
... FROM ratings
... INNER JOIN movies
... ON movies.id = ratings.movie_id
... GROUP BY movie_id
... ORDER BY average_rating DESC
... LIMIT 5
... """
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... for movie in cursor.fetchall():
... print(movie)
...
('Night of the Living Dead', Decimal('9.90000'))
('The Godfather', Decimal('9.90000'))
('Avengers: Endgame', Decimal('9.75000'))
('Eternal Sunshine of the Spotless Mind', Decimal('8.90000'))
('Beasts of No Nation', Decimal('8.70000'))
As shown above, Night of the Living Dead and The Godfather are tied as the highest-rated movies in your online_movie_rating
Datenbank.
To find the name of the reviewer who gave the most ratings, write the following query:
>>>>>> select_movies_query = """
... SELECT CONCAT(first_name, " ", last_name), COUNT(*) as num
... FROM reviewers
... INNER JOIN ratings
... ON reviewers.id = ratings.reviewer_id
... GROUP BY reviewer_id
... ORDER BY num DESC
... LIMIT 1
... """
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... for movie in cursor.fetchall():
... print(movie)
...
('Mary Cooper', 4)
Mary Cooper
is the most frequent reviewer in this database. As seen above, it doesn’t matter how complicated the query is because it’s ultimately handled by the MySQL server. Your process for executing a query will always remain the same:pass the query to cursor.execute()
and fetch the results using .fetchall()
.
Updating and Deleting Records From the Database
In this section, you’ll be updating and deleting records from the database. Both of these operations can be performed on either a single record or multiple records in the table. You’ll select the rows that need to be modified using the WHERE
Klausel.
UPDATE
Command
One of the reviewers in your database, Amy Farah Fowler
, is now married to Sheldon Cooper
. Her last name has now changed to Cooper
, so you need to update your database accordingly. For updating records, MySQL uses the UPDATE
statement:
update_query = """
UPDATE
reviewers
SET
last_name = "Cooper"
WHERE
first_name = "Amy"
"""
with connection.cursor() as cursor:
cursor.execute(update_query)
connection.commit()
The code passes the update query to cursor.execute()
, and .commit()
brings the required changes to the reviewers
Tabelle.
Hinweis: In the UPDATE
query, the WHERE
clause helps specify the records that need to be updated. If you don’t use WHERE
, then all records will be updated!
Suppose you need to provide an option that allows reviewers to modify ratings. A reviewer will provide three values, movie_id
, reviewer_id
, and the new rating
. The code will display the record after performing the specified modification.
Assuming that movie_id = 18
, reviewer_id = 15
, and the new rating = 5.0
, you can use the following MySQL queries to perform the required modification:
UPDATE
ratings
SET
rating = 5.0
WHERE
movie_id = 18 AND reviewer_id = 15;
SELECT *
FROM ratings
WHERE
movie_id = 18 AND reviewer_id = 15;
The above queries first update the rating and then display it. You can create a complete Python script that establises a connection with the database and allows the reviewer to modify a rating:
from getpass import getpass
from mysql.connector import connect, Error
movie_id = input("Enter movie id: ")
reviewer_id = input("Enter reviewer id: ")
new_rating = input("Enter new rating: ")
update_query = """
UPDATE
ratings
SET
rating = "%s"
WHERE
movie_id = "%s" AND reviewer_id = "%s";
SELECT *
FROM ratings
WHERE
movie_id = "%s" AND reviewer_id = "%s"
""" % (
new_rating,
movie_id,
reviewer_id,
movie_id,
reviewer_id,
)
try:
with connect(
host="localhost",
user=input("Enter username: "),
password=getpass("Enter password: "),
database="online_movie_rating",
) as connection:
with connection.cursor() as cursor:
for result in cursor.execute(update_query, multi=True):
if result.with_rows:
print(result.fetchall())
connection.commit()
except Error as e:
print(e)
Save this code to a file named modify_ratings.py
. The above code uses %s
placeholders to insert the received input in the update_query
Schnur. For the first time in this tutorial, you have multiple queries inside a single string. To pass multiple queries to a single cursor.execute()
, you need to set the method’s multi
argument to True
.
If multi
is True
, then cursor.execute()
returns an iterator. Each item in the iterator corresponds to a cursor
object that executes a statement passed in the query. The above code runs a for
loop on this iterator and then calls .fetchall()
on each cursor
Objekt.
Hinweis: Running .fetchall()
on all cursor objects is important. To execute a new statement on the same connection, you must ensure that there are no unread results from previous executions. If there are unread results, then you’ll receive an exception.
If no result set is fetched on an operation, then .fetchall()
raises an exception. To avoid this error, in the code above you use the cursor.with_rows
property, which indicates whether the most recently executed operation produced rows.
While this code should solve your purpose, the WHERE
clause is a prime target for web hackers in its current state. It’s vulnerable to what is called a SQL injection attack, which can allow malicious actors to either corrupt or misuse your database.
Warning :Don’t try the below inputs on your database! They will corrupt your table and you’ll need to recreate it.
For example, if a user sends movie_id=18
, reviewer_id=15
, and the new rating=5.0
as input, then the output looks like this:
$ python modify_ratings.py
Enter movie id: 18
Enter reviewer id: 15
Enter new rating: 5.0
Enter username: <user_name>
Enter password:
[(18, 15, Decimal('5.0'))]
The rating
with movie_id=18
and reviewer_id=15
has been changed to 5.0
. But if you were hacker, then you might send a hidden command in your input:
$ python modify_ratings.py
Enter movie id: 18
Enter reviewer id: 15"; UPDATE reviewers SET last_name = "A
Enter new rating: 5.0
Enter username: <user_name>
Enter password:
[(18, 15, Decimal('5.0'))]
Again, the output shows that the specified rating
has been changed to 5.0
. What’s changed?
The hacker sneaked in an update query while entering the reviewer_id
. The update query, update reviewers set last_name = "A
, changes the last_name
of all records in the reviewers
table to "A"
. You can see this change if you print out the reviewers
Tabelle:
>>> select_query = """
... SELECT first_name, last_name
... FROM reviewers
... """
>>> with connection.cursor() as cursor:
... cursor.execute(select_query)
... for reviewer in cursor.fetchall():
... print(reviewer)
...
('Chaitanya', 'A')
('Mary', 'A')
('John', 'A')
('Thomas', 'A')
('Penny', 'A')
('Mitchell', 'A')
('Wyatt', 'A')
('Andre', 'A')
('Sheldon', 'A')
('Kimbra', 'A')
('Kat', 'A')
('Bruce', 'A')
('Domingo', 'A')
('Rajesh', 'A')
('Ben', 'A')
('Mahinder', 'A')
('Akbar', 'A')
('Howard', 'A')
('Pinkie', 'A')
('Gurkaran', 'A')
('Amy', 'A')
('Marlon', 'A')
The above code displays the first_name
and last_name
for all records in the reviewers
table. The SQL injection attack corrupted this table by changing the last_name
of all records to "A"
.
There’s a quick fix to prevent such attacks. Don’t add the query values provided by the user directly to your query string. Instead, update the modify_ratings.py
script to send these query values as arguments to .execute()
:
from getpass import getpass
from mysql.connector import connect, Error
movie_id = input("Enter movie id: ")
reviewer_id = input("Enter reviewer id: ")
new_rating = input("Enter new rating: ")
update_query = """
UPDATE
ratings
SET
rating = %s
WHERE
movie_id = %s AND reviewer_id = %s;
SELECT *
FROM ratings
WHERE
movie_id = %s AND reviewer_id = %s
"""
val_tuple = (
new_rating,
movie_id,
reviewer_id,
movie_id,
reviewer_id,
)
try:
with connect(
host="localhost",
user=input("Enter username: "),
password=getpass("Enter password: "),
database="online_movie_rating",
) as connection:
with connection.cursor() as cursor:
for result in cursor.execute(update_query, val_tuple, multi=True):
if result.with_rows:
print(result.fetchall())
connection.commit()
except Error as e:
print(e)
Notice that the %s
placeholders are no longer in string quotes. Strings passed to the placeholders might contain some special characters. If necessary, these can be correctly escaped by the underlying library.
cursor.execute()
makes sure that the values in the tuple received as argument are of the required data type. If a user tries to sneak in some problematic characters, then the code will raise an exception:
$ python modify_ratings.py
Enter movie id: 18
Enter reviewer id: 15"; UPDATE reviewers SET last_name = "A
Enter new rating: 5.0
Enter username: <user_name>
Enter password:
1292 (22007): Truncated incorrect DOUBLE value: '15";
UPDATE reviewers SET last_name = "A'
cursor.execute()
will raise an exception if it finds any unwanted characters in the user input. You should use this approach whenever you incorporate user input in a query. There are other ways of preventing SQL injection attacks as well.
DELETE
Command
Deleting records works very similarly to updating records. You use the DELETE
statement to remove selected records.
Hinweis: Deleting is an irreversible Prozess. If you don’t use the WHERE
clause, then all records from the specified table will be deleted. You’ll need to run the INSERT INTO
query again to get back the deleted records.
It’s recommended that you first run a SELECT
query with the same filter to make sure that you’re deleting the right records. For example, to remove all ratings given by reviewer_id = 2
, you should first run the corresponding SELECT
Abfrage:
>>> select_movies_query = """
... SELECT reviewer_id, movie_id FROM ratings
... WHERE reviewer_id = 2
... """
>>> with connection.cursor() as cursor:
... cursor.execute(select_movies_query)
... for movie in cursor.fetchall():
... print(movie)
...
(2, 7)
(2, 8)
(2, 12)
(2, 23)
The above code snippet outputs the reviewer_id
and movie_id
for records in the ratings
table where reviewer_id = 2
. Once you’ve confirmed that these are the records that you need to delete, you can run a DELETE
query with the same filter:
delete_query = "DELETE FROM ratings WHERE reviewer_id = 2"
with connection.cursor() as cursor:
cursor.execute(delete_query)
connection.commit()
With this query, you remove all ratings given by the reviewer with reviewer_id = 2
from the ratings
Tabelle.
Other Ways to Connect Python and MySQL
In this tutorial, you saw MySQL Connector/Python, which is the officially recommended means of interacting with a MySQL database from a Python application. There are two other popular connectors:
-
mysqlclient is a library that is a close competitor to the official connector and is actively updated with new features. Because its core is written in C, it has better performance than the pure-Python official connector. A big drawback is that it’s fairly difficult to set up and install, especially on Windows.
-
MySQLdb is a legacy software that’s still used in commercial applications. It’s written in C and is faster than MySQL Connector/Python but is available only for Python 2.
These connectors act as interfaces between your program and a MySQL database, and you send your SQL queries through them. But many developers prefer using an object-oriented paradigm rather than SQL queries to manipulate data.
Object-relational mapping (ORM) is a technique that allows you to query and manipulate data from a database directly using an object-oriented language. An ORM library encapsulates the code needed to manipulate data, which eliminates the need to use even a tiny bit of SQL. Here are the most popular Python ORMs for SQL-based databases:
-
SQLAlchemy is an ORM that facilitates communication between Python and other SQL databases. You can create different engines for different databases like MySQL, PostgreSQL, SQLite, and so on. SQLAlchemy is commonly used alongside the pandas library to provide complete data-handling functionality.
-
peewee is a lightweight and fast ORM that’s quick to set up. This is quite useful when your interaction with the database is limited to extracting a few records. For example, if you need to copy selected records from a MySQL database into a CSV file, then peewee might be your best choice.
-
Django ORM is one of the most powerful features of Django and is supplied alongside the Django web framework. It can interact with a variety of databases such as SQLite, PostgreSQL, and MySQL. Many Django-based applications use the Django ORM for data modeling and basic queries but often switch to SQLAlchemy for more complex requirements.
You might find one of these approaches to be more suitable for your application. If you’re not sure which one to use, then it’s best to go with the officially recommended MySQL Connector/Python that you saw in action in this tutorial.
Schlussfolgerung
In this tutorial, you saw how to use MySQL Connector/Python to integrate a MySQL database with your Python application. You also saw some unique features of a MySQL database that differentiate it from other SQL databases.
Along the way, you learned some programming best practices that are worth considering when it comes to establishing a connection, creating tables, and inserting and updating records in a database application. You also developed a sample MySQL database for an online movie rating system and interacted with it directly from your Python application.
In this tutorial, you learned how to:
- Connect your Python app with a MySQL database
- Bring data from a MySQL database into Python for further analysis
- Execute SQL queries from your Python application
- Handle exceptions while accessing the database
- Prevent SQL injection attacks on your application
If you’re interested, Python also has connectors for other DBMSs like MongoDB and PostgreSQL. For more information, check out Python Database Tutorials.