🐥

PythonからMySQLにアクセスしたい

2023/01/29に公開

PythonでFlaskを触っていると、データベースを使いたくなることがあります。アクセスするためのドライバーには下記のようなものがありますが、今回最も基本的なmysql-connector-pythonを使うことにします。

mysql-connector-pythonとはなにか?

mysql-connector-pythonは、Oracle社などが提供しているドライバーで、PEP 249 – Python Database API Specification v2.0に準拠しています[1]。PEPは、PEP8 – Style Guide for Python Codeといったコーディング規約のイメージが強いですが、下記のように、様々な仕様がPEPという文書で書かれています。

大事なことはPEPに書いてあります。
PEP はPython 拡張提案(Python Enhancement Proposal)の略語です。 大きな変更が行われるときは、PEPという文書が書かれて議論されます。なぜその機能が追加されたかがわかります。却下された議論についてのPEPが残るので後で同じようなリクエストが出たときにわかりやすいです。

Pythonの紹介 - PyQ

つまり、PEP249はPythonからデータベースにアクセスする際の基本的な設計を標準化しているものです。sqlite3のドライバーもPEP249に準拠しています。pythonにおけるデータベースについてのドキュメントがsqlite3は一番充実しています。もし躓いたら、sqlite3 --- SQLite データベースに対する DB-API 2.0 インターフェースを見るのもおすすめです。

実際に使ってみる

検証環境

検証環境をDockerにて作成しました。本記事で書いた一部のコードをmain.pyに記入しています。docker compose upを使うことですぐに実行結果を確認することができます。

https://github.com/gorira-tatsu/mcp-test

  • 検証環境
    • Python 3.12
    • MySQL 8.0

検証にて使用したテーブル

CREATE TABLE users (
  id INT NOT NULL AUTO_INCREMENT,
  username VARCHAR(20) UNIQUE NOT NULL,
  password VARCHAR(64) NOT NULL,
  email VARCHAR(30) UNIQUE NOT NULL,
  PRIMARY KEY (id)
);
num username password email
1 gorira gorira gorira@example.com
2 panda panda panda@example.com
3 rabbit rabbit rabbit@example.com
4 dog dog dog@example.com
5 cat cat cat@example.com

コード例

import mysql.connector
connect = mysql.connector.connect(host='db', database='test', user='test', password='test')

hostにはホストを指定し、databaseにはデータベース名を、userpasswordはMySQLにて使われているユーザー、パスワードを指定することができます。ほかに指定したい場合は、MySQLドキュメントに公開されているMySQL :: MySQL Connector/Python Developer Guide :: 7.1 Connector/Python Connection Argumentsを一読ください。

cur = connect.cursor(buffered=True)

cur.execute('SELECT * FROM users')
print(cur.fetchone())
print(cur.fetchmany(2))
print(cur.fetchall())

#out
# (1, 'gorira', 'gorira', 'gorira@example.com')
# [(2, 'panda', 'panda', 'panda@example.com'), (3, 'rabbit', 'rabbit', 'rabbit@example.com')]
# [(4, 'dog', 'dog', 'dog@example.com'), (5, 'cat', 'cat', 'cat@example.com')]

cursor()buffered=Trueを渡すと、自動的にバッファリングされます。詳しい仕様についてはMySQL :: MySQL Connector/Python Developer Guide :: 10.6.1 cursor.MySQLCursorBuffered Classをご覧ください。

データベースに変更を行う文を指定した場合(INSERT文やDELETE文など)はcommit()を必ずしなければ変更されません。rollback()はデータベースに変更を行ったとき、ロールバックをすることができる関数です。SELECT文にて返されたレコードはfetchを使うことで容易にアクセスすることができます。fetchtupleで返されます。fetchone()は1レコードしか返されませんが、fetchmany()の引数に数字を指定することでその分のレコードが返されます。またSELECT文にて得たレコードのすべてを得る場合にはfetchall()を使います。通常、fetchで既に得たレコードは返されないことに注意してください。

cur = connect.cursor(dictionary=True)
try:
    cur.execute('SELECT * FROM users')
    print(cur.fetchone())
#out
# {'num': 1, 'username': 'gorira', 'password': 'gorira', 'email': 'gorira@example.com'}

fetchにて返される型をDictionary型に指定したい場合は、cursorに上記のような引数を渡してあげることで、カラム名をkeyとした扱いやすい形になります。cursorに渡す引数の詳細についてはMySQL :: MySQL Connector/Python Developer Guide :: 10.5 cursor.MySQLCursor Classをご覧ください。

try:
    cur.execute("INSERT INTO users (username,password,email) VALUES ('gorira','gorira','gorira@examle.com')")
    connect.commit()
except mysql.connector.errors.IntegrityError:
    print("Already inserted.")

データベースのテーブルにUNIQUEが設定されている場合、同じ文字列などを挿入しようとすると例外が発生します。これは上記のように書くことで回避することができます。その他の例外について詳しく知りたい場合はPEP 249 – Python Database API Specification v2.0 Exceptionsをご覧ください。

詳しく学ぶには

これまでよく使う関数などを紹介してきましたが、もっと詳しく知りたい方はこちらをご覧ください。

MySQL Connector/Python Developer Guide

PEP 249 – Python Database API Specification v2.0

sqlite3 --- SQLite データベースに対する DB-API 2.0 インターフェース

https://github.com/gorira-tatsu/mcp-test

脚注
  1. MySQL Connector/Python enables Python programs to access MySQL databases, using an API that is compliant with the Python Database API Specification v2.0 (PEP 249). by MySQL :: MySQL Connector/Python Developer Guide :: 1 Introduction to MySQL Connector/Python ↩︎

GitHubで編集を提案

Discussion