原文链接:http://zetcode.com/databases/mysqlpythontutorial/
翻译作者:kodango dangoakachan at foxmail dot com
译文链接:
a. http://kodango.com/mysql-python-tutorial-part-one
b. http://kodango.com/mysql-python-tutorial-part-two

关于本教程

这是一份介绍用Python语言操作MySQL数据库的教程,覆盖了基础的Python MySQL编程内容。本教程中使用了MySQLdb模块,文中的例子在Ubuntu系统下运行和测试。

译者注:我使用ArchLinux,会在文中添加与ArchLinux相关的内容,例子也会一一在ArchLinux下验证。

在本站中,有许多与本文类似的教程,其中包括PostgreSQL PythonMySQL Visual BasicMySQL PHP。如果你需要更新与Python语言相关的知识,在这里还有一份完整的Python教程。你也可以考虑阅读MySQL教程

关于MySQL数据库

MySQL是一个领先的开源数据库管理系统。它是一个多用户,多线程的数据库管理系统。MySQL在网上非常流行,它与Linux、Apache、PHP一起组成LAMP平台,这是一个非常流行的Web平台。目前,MySQL是由甲骨文拥有。MySQL数据库可用于最重要的几个操作系统上。它能够运行在BSD UNIX,Linux,Windows或Mac操作系统之上。

Wikipedia和YouTube均使用MySQL数据库。这些站点每天处理数百万的查询次数。MySQL包含服务器系统和嵌入式系统两个版本。

开始之前

我们需要安装几个软件包,才能确保本文的例子可以正确地执行。如果你的电脑上没有安装MySQL,我们必须先安装它:

Ubuntu
$ sudo apt-get install mysql-server

ArchLinux
$ sudo pacman -S mysql
或者
$ yaourt xampp

以上的命令会安装MySQL服务器,还包括一些相关的软件包。在安装的过程中,可能会有提示让你输入MySQL的Root账号的密码。

Ubuntu
$ apt-cache search MySQLdb
python-mysqldb - A Python interface to MySQL
python-mysqldb-dbg - A Python interface to MySQL (debug extension)
bibus - bibliographic database
eikazo - graphical frontend for SANE designed for mass-scanning

ArchLinux
# sudo pacman -Ss mysql | grep python
extra/mysql-python 1.2.3-3
    MySQL support for Python

我们并不知道MySQLdb模块的具体包名称,我们使用apt-cache命令来搜索。

译者注:ArchLinux下用pacman -Ss来搜索。

Ubuntu
$ sudo apt-get install python-mysqldb

ArchLinux
$ sudo pacman -S mysql-python

在这里,我们安装好MySQL数据库的Python编程接口,其中包括_mysql和MySQLdb模块。

接下来,我们会为本文的例子创建一个新的数据库和数据库用户,我们使用MySQL客户端来操作:

$ mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 30
Server version: 5.0.67-0ubuntu6 (Ubuntu)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema | 
| mysql              | 
+--------------------+
2 rows in set (0.00 sec)

译者注:如果是安装Xampp,MySQL客户端位置在/opt/lampp/bin/mysql(具体位置以实际为主)

我们使用root账号连接到数据库上,并用通过SHOW DATABASES语句列出所有数据库名称。

mysql> CREATE DATABASE testdb;
Query OK, 1 row affected (0.02 sec)

我们创建一个新的数据库testdb,在本文的例子中都会用到这个数据库。

mysql> CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'test623';
Query OK, 0 rows affected (0.00 sec)

mysql> USE testdb;
Database changed

mysql> GRANT ALL ON testdb.* TO 'testuser'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> quit;
Bye

我们创建一个新的数据库用户,并且将testdb数据库中的所有表的操作权限全部授权给这个用户。

_mysql模块

_mysql模块直接封装实现了MySQL的C语言API函数。它与Python标准的数据库API接口不兼容。通常,程序员都更加喜欢面向对象的MySQLdb模块。我们也会更加关注后一个模块。在这里,我们只是给出一个使用_mysql模块编程的小例子。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import _mysql
import sys

con = None

try:

    con = _mysql.connect('localhost', 'testuser', 
        'test623', 'testdb')
        
    con.query("SELECT VERSION()")
    result = con.use_result()
    
    print "MySQL version: %s" % \
        result.fetch_row()[0]
    
except _mysql.Error, e:
  
    print "Error %d: %s" % (e.args[0], e.args[1])
    sys.exit(1)

finally:
    
    if con:
        con.close()

这个例子会获取并打印MySQL数据库的版本,为此我们使用SELECT VERSION()这条SQL语句。

MySQLdb模块

MySQLdb是在_mysql模块的基础上进一步进行封装,并且与Python的标准数据库API接口兼容,这使得代码更易于移植。使用这个模块是操作MySQL数据库的首选方法。

第一个例子

在第一个例子中,我们来获取MySQL数据库的版本。

!/usr/bin/python
# -*- coding: utf-8 -*-

import MySQLdb as mdb
import sys

con = None

try:

    con = mdb.connect('localhost', 'testuser', 
        'test623', 'testdb');

    cur = con.cursor()
    cur.execute("SELECT VERSION()")

    data = cur.fetchone()
    
    print "Database version : %s " % data
    
except mdb.Error, e:
  
    print "Error %d: %s" % (e.args[0],e.args[1])
    sys.exit(1)
    
finally:    
        
    if con:    
        con.close()

在这个脚本中,我们连接到testdb数据库并执行 SELECT VERSION()语句。该脚本返回MySQL数据库的版本号,并打印到终端。

import MySQLdb as mdb

我们导入MySQLdb模块。

con = None

我们将con变量初始化成None。在无法创建数据库连接的时候(例如硬盘空间已满),我们不能定义该数据库连接变量。这将会导致在finally语句中执行出错。

con = mdb.connect('localhost', 'testuser', 
    'test623', 'testdb');

我们连接到数据库中,其中connect()方法有四个参数。第一个是MySQL数据库所在的主机地址,在我们的例子中为'localhost';第二个参数是数据库的用户名,其实是该用户的密码;最后一个参数是数据库的名称。

cur = con.cursor()
cur.execute("SELECT VERSION()")

一旦连接成为,我们将会得到一个cursor(游标)对象。这个cursor对象用来遍历结果集中的记录。我们通过调用该curor对象的execute()方法来执行SQL语句。

data = cur.fetchone()

我们开始获取数据,由于我们只取回一个记录,因此我们调用fetchone()方法。

print "Database version : %s " % data

我们将取回的数据打印到终端。

except mdb.Error, e:
  
    print "Error %d: %s" % (e.args[0],e.args[1])
    sys.exit(1)

我们检查错误,这是很重要的,因为与在与数据库打交道的过程中很容易出错。

finally:    
        
    if con:    
        con.close()

最后一步,我们释放连接的资源。

$ ./version.py
Database version : 5.5.9 

输出结果如上所示。

创建并填充表

我们创建一个表,并在其中填入一些数据。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import MySQLdb as mdb
import sys

con = mdb.connect('localhost', 'testuser', 'test623', 'testdb');

with con:
    
    cur = con.cursor()
    cur.execute("CREATE TABLE IF NOT EXISTS \
        Writers(Id INT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(25))")
    cur.execute("INSERT INTO Writers(Name) VALUES('Jack London')")
    cur.execute("INSERT INTO Writers(Name) VALUES('Honore de Balzac')")
    cur.execute("INSERT INTO Writers(Name) VALUES('Lion Feuchtwanger')")
    cur.execute("INSERT INTO Writers(Name) VALUES('Emile Zola')")
    cur.execute("INSERT INTO Writers(Name) VALUES('Truman Capote')")

译者注:在这里使用了with..的语法,在退出with语句之前,会执行con对象的__exit__方法,猜测在该方法中会调用commit方法提交事务,同PySqlite学习笔记介绍的一样。

我们创建一张记录作家名字的数据库表,并往其中添加五位作者。

cur.execute("CREATE TABLE IF NOT EXISTS \
    Writers(Id INT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(25))")

这条SQL语句创建了一个名为Writers的新数据库,它包含Id和Name两列。

cur.execute("INSERT INTO Writers(Name) VALUES('Jack London')")
cur.execute("INSERT INTO Writers(Name) VALUES('Honore de Balzac')")
...

我们使用INSERT语句插入作者到表中, 这里我们添加两行。

mysql> SELECT * FROM Writers;
+----+-------------------+
| Id | Name              |
+----+-------------------+
|  1 | Jack London       |
|  2 | Honore de Balzac  |
|  3 | Lion Feuchtwanger |
|  4 | Emile Zola        |
|  5 | Truman Capote     |
+----+-------------------+
5 rows in set (0.00 sec)

在脚本执行之后,我们通过MySQL的客户端工具来查询Writers表中的所有数据。

取回数据

现在,在往表中插入一些数之后,我们想要将数据取回。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import MySQLdb as mdb
import sys


con = mdb.connect('localhost', 'testuser', 
        'test623', 'testdb');

with con: 

    cur = con.cursor()
    cur.execute("SELECT * FROM Writers")

    rows = cur.fetchall()

    for row in rows:
        print row

在这个例子中,我们从Writers表中取回所有数据。

cur.execute("SELECT * FROM Writers")

这条SQL语句从Writers表中查询所有的数据。

rows = cur.fetchall()

fetchall()方法获取所有记录。它返回一个结果集,该结果集其实是一个包含元组的元组。在元组内部的第一个元组代码表中的一行。

for row in rows:
    print row

我们以行的方式将数据打印到终端。

$ ./retrieve.py
(1L, 'Jack London')
(2L, 'Honore de Balzac')
(3L, 'Lion Feuchtwanger')
(4L, 'Emile Zola')
(5L, 'Truman Capote')

这是本例子的输出结果。

一次性返回所有的数据未必可行,我们可以取逐行依次取回。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import MySQLdb as mdb
import sys


con = mdb.connect('localhost', 'testuser', 
    'test623', 'testdb');

with con:

    cur = con.cursor()
    cur.execute("SELECT * FROM Writers")

    numrows = int(cur.rowcount)

    for i in range(numrows):
        row = cur.fetchone()
        print row[0], row[1]

我们仍然从Writers表中取回数据,并打印到终端。这次我们逐行获取数据。

numrows = int(cur.rowcount)

这里我们首先确认SQL语句查询结果中包含的行数。

for i in range(numrows):
    row = cur.fetchone()
    print row[0], row[1]

我们使用fetchone()方法逐行获取数据。

$ ./retrieve2.py
1 Jack London
2 Honore de Balzac
3 Lion Feuchtwanger
4 Emile Zola
5 Truman Capote

该例子返回的结果。

译者注:由于篇幅有限,余下内容请看下一篇文章