ZetCode

PyMySQL

最后修改于 2024 年 1 月 29 日

PyMySQL 教程展示了如何使用 PyMySQL 模块在 Python 中编程 MySQL。

PyMySQL

PyMySQL 是一个纯 Python 的 MySQL 客户端库,基于 PEP 249。大多数公共 API 与 mysqlclient 和 MySQLdb 兼容。PyMySQL 可与 MySQL 5.5+ 和 MariaDB 5.5+ 配合使用。

MySQL 是领先的开源数据库管理系统。它是一个多用户、多线程的数据库管理系统。MySQL 在 Web 上尤其受欢迎。

cities_mysql.sql
USE testdb;
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), population INT);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);

在本教程中,我们使用 cities 表。

PyMySQL 安装

$ sudo pip3 install pymysql

我们使用 pip3 工具来安装 PyMySQL。

PyMySQL 版本示例

在下面的示例中,我们获取 MySQL 的版本。

version.py
#!/usr/bin/python

import pymysql

con = pymysql.connect('localhost', 'user7',
    's$cret', 'testdb')

try:

    with con.cursor() as cur:

        cur.execute('SELECT VERSION()')

        version = cur.fetchone()

        print(f'Database version: {version[0]}')

finally:

    con.close()

在 MySQL 中,我们可以使用 SELECT VERSION 来获取 MySQL 的版本。

import pymysql

我们导入 pymysql 模块。

con = pymysql.connect('localhost', 'user7',
    's$cret', 'testdb')

我们使用 connect 连接到数据库。我们传递四个参数:主机名、MySQL 用户名、密码和数据库名。

with con.cursor() as cur:

使用 with 关键字,Python 解释器会自动释放资源。它还提供错误处理。我们获取一个游标对象,该对象用于遍历结果集中的记录。

cur.execute('SELECT VERSION()')

我们调用游标的 execute 函数并执行 SQL 语句。

version = cur.fetchone()

fetchone 函数获取查询结果集的下一行,返回一个单一序列,或者在没有更多可用数据时返回 None

print(f'Database version: {version[0]}')

我们打印数据库的版本。

finally:

    con.close()

pymysql 模块不实现连接资源的自动处理;我们需要在 finally 子句中显式地使用 close 关闭连接。

$ ./version.py
Database version: 10.3.23-MariaDB-1

PyMySQL fetchAll

fetchAll 方法检索查询结果的所有(剩余)行,并将它们作为序列的序列返回。

fetch_all.py
#!/usr/bin/python

import pymysql

con = pymysql.connect('localhost', 'user7',
    's$cret', 'testdb')

try:

    with con.cursor() as cur:

        cur.execute('SELECT * FROM cities')

        rows = cur.fetchall()

        for row in rows:
            print(f'{row[0]} {row[1]} {row[2]}')

finally:

    con.close()

在示例中,我们从数据库表中检索所有城市。

cur.execute('SELECT * FROM cities')

此 SQL 语句从 cities 表中选择所有数据。

rows = cur.fetchall()

fetchall 函数获取所有记录。它返回一个结果集。从技术上讲,它是一个元组的元组。每个内部元组代表表中的一行。

for row in rows:
    print(f'{row[0]} {row[1]} {row[2]}')

我们将数据逐行打印到控制台。

$ ./fetch_all.py
1 Bratislava 432000
2 Budapest 1759000
3 Prague 1280000
4 Warsaw 1748000
5 Los Angeles 3971000
6 New York 8550000
7 Edinburgh 464000
8 Berlin 3671000

PyMySQL 字典游标

默认游标返回元组的元组形式的数据。当我们使用字典游标时,数据将以 Python 字典的形式发送。这样我们就可以通过列名引用数据。

dictionary_cursor.py
#!/usr/bin/python

import pymysql
import pymysql.cursors

con = pymysql.connect(host='localhost',
        user='user7',
        password='s$cret',
        db='testdb',
        charset='utf8mb4',
        cursorclass=pymysql.cursors.DictCursor)

try:

    with con.cursor() as cur:

        cur.execute('SELECT * FROM cities')

        rows = cur.fetchall()

        for row in rows:
            print(row['id'], row['name'])

finally:

    con.close()

在此示例中,我们使用字典游标获取 cities 表的前几行。

con = pymysql.connect(host='localhost',
    user='user7',
    password='s$cret',
    db='testdb',
    charset='utf8mb4',
    cursorclass=pymysql.cursors.DictCursor)

connect 函数中,我们将 pymysql.cursors.DictCursor 值传递给 cursorclass 参数。

for row in rows:
    print(row['id'], row['name'])

我们通过 cities 表的列名来引用数据。

PyMySQL 列标题

接下来我们将展示如何打印数据库表中的数据及其列标题。

column_headers.py
#!/usr/bin/python

import pymysql

con = pymysql.connect('localhost', 'user7',
    's$cret', 'testdb')

try:

    with con.cursor() as cur:

        cur.execute('SELECT * FROM cities')

        rows = cur.fetchall()

        desc = cur.description

        print(f'{desc[0][0]:<8} {desc[1][0]:<15} {desc[2][0]:>10}')

        for row in rows:
            print(f'{row[0]:<8} {row[1]:<15} {row[2]:>10}')

finally:

    con.close()

列名被视为元数据。它们是从游标对象获得的。

desc = cur.description

游标的 description 属性返回有关查询每个结果列的信息。

print(f'{desc[0][0]:<8} {desc[1][0]:<15} {desc[2][0]:>10}')

在这里,我们打印并格式化表的列名。

for row in rows:
    print(f'{row[0]:<8} {row[1]:<15} {row[2]:>10}')

我们遍历并打印数据。

$ ./column_headers.py 
id       name            population
1        Bratislava          432000
2        Budapest           1759000
3        Prague             1280000
4        Warsaw             1748000
5        Los Angeles        3971000
6        New York           8550000
7        Edinburgh           464000
8        Berlin             3671000

PyMySQL 转义参数

传递给 execute 方法的参数会出于安全原因进行转义;这是为了防止 SQL 注入攻击。

escaped.py
#!/usr/bin/python

import pymysql

con = pymysql.connect('localhost', 'user7', 
    's$cret', 'testdb')

# user input
myid = 4

try: 

    with con.cursor() as cur:

            
        cur.execute('SELECT * FROM cities WHERE id=%s', myid) 
        
        cid, name, population  = cur.fetchone()
        print(cid, name, population)

finally:

    con.close()

在示例中,我们获取具有指定 ID 的行。

cur.execute('SELECT * FROM cities WHERE id=%s', myid) 

我们使用由 %s 标记标识的占位符。在执行 SQL 语句之前,值会被绑定到它们的占位符。

$ ./escaped.py 
4 Warsaw 1748000

PyMySQL 受影响的行数

rowcount 是一个只读游标属性,它指定最后一个 SELECT、UPDATE 或 INSERT 语句产生的行数。

affected_rows.py
#!/usr/bin/python

import pymysql

con = pymysql.connect('localhost', 'user7',
   's$cret', 'testdb')

try:

    with con.cursor() as cur:

        cur.execute('SELECT * FROM cities WHERE id IN (1, 2, 3)')

        print(f'The query affected {cur.rowcount} rows')

finally:

    con.close()

在示例中,我们有一个选择三行的 SELECT 语句。

print(f'The query affected {cur.rowcount} rows')

我们构建一条消息来显示受影响的行数。

$ ./affected_rows.py
The query affected 3 rows

PyMySQL 插入行

使用 INSERT INTO SQL 语句插入新行。

insert_row.py
#!/usr/bin/python

import pymysql

con = pymysql.connect('localhost', 'user7', 
    's$cret', 'testdb')

city = (9, 'Kiev', 2887000)

try: 

    with con.cursor() as cur:

        cur.execute('INSERT INTO cities VALUES(%s, %s, %s)', 
            (city[0], city[1], city[2])) 
        con.commit()

        print('new city inserted')

finally:

    con.close()

在示例中,我们将一个新城市插入表中。

cur.execute('INSERT INTO cities VALUES(%s, %s, %s)', 
    (city[0], city[1], city[2])) 
con.commit()

pymysql 中,自动提交默认是关闭的。我们需要调用 commit 来执行更改。

来源

PyMySQL 文档

在本文中,我们一直在使用 PyMySQL 模块在 Python 中编程 MySQL 数据库。

作者

我叫 Jan Bodnar,是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Python 教程