NOTE(2017-11-18): MySQLdb 不支持 Python 3,而 Python 3 是主流,因此就没有学习的必要了。html
环境:MySQL 5.6.27, Ubuntu 15.10 64-bitpython
我的笔记,可读性较差。寻教程请移步:MySQL Python tutorialmysql
官方简介sql
MySQLdb is an thread-compatible interface to the popular MySQL
database server that provides the Python database API.数据库
$ apt-get install python-dev libmysqlclient-dev $ pip install MySQL-python
详见:How to install Python MySQLdb module using pip?api
$ sudo apt-get install python-mysqldb
MySQLdb 安装好后,有两个模块或方式可用。模块 _mysql
提供的是相似于 MySQL C 接口的 API,而模块 MySQLdb
在 _mysql
基础上又作了进一步封装,使之符合 Python 的数据库 API 规范。推荐使用后者。安全
使用 _mysql
的例子:ide
import _mysql import sys try: con = _mysql.connect('localhost', 'root', '******', 'test') 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()
改用 MySQLdb
:性能
import MySQLdb as mdb import sys try: con = mdb.connect('localhost', 'root', '******', 'test') cur = con.cursor() cur.execute('select version()') ver = cur.fetchone() print 'MySQL version: %s' % ver except mdb.Error, e: print 'Error %d: %s' % (e.args[0], e.args[1]) sys.exit(1) finally: if con: con.close()
# coding: utf-8 import MySQLdb as mdb con = mdb.connect('localhost', 'root', '******', 'test') with con: cur = con.cursor() cur.execute('drop table if exists writers') cur.execute('create table writers(id int primary key auto_increment,\ name varchar(25)) default charset utf8') 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")') cur.execute('insert into writers(name) values("曹雪芹")')
fetchall
import MySQLdb as mdb con = mdb.connect('localhost', 'root', '******', 'test') with con: cur = con.cursor() cur.execute('select * from writers') # 结果集 rows 为元组(tuple)的元组,每个元组表明了表中的一行。 rows = cur.fetchall() for row in rows: print row
fetchone
import MySQLdb as mdb con = mdb.connect('localhost', 'root', '******', 'test') with con: cur = con.cursor() cur.execute('select * from writers') for i in range(cur.rowcount): row = cur.fetchone() print row
import MySQLdb as mdb con = mdb.connect('localhost', 'root', '******', 'test') def test_dict_cursor(): with con: cur = con.cursor(mdb.cursors.DictCursor) # 字典 cursor cur.execute('select * from writers limit 4') # rows 为字典的元组 rows = cur.fetchall() for row in rows: print row['id'], row['name'] # 经过列名访问结果
import MySQLdb as mdb con = mdb.connect('localhost', 'root', '******', 'test') with con: cur = con.cursor() cur.execute('select * from writers limit 4') rows = cur.fetchall() # 元组的元组,每个元组对应一个结果列,元组的第一个元素为列名。 desc = cur.description # 打印前两个结果列的列名。 print '%s %3s' % (desc[0][0], desc[1][0]) for row in rows: print '%2s %3s' % row
Prepared Statements 能够提升安全性和性能,特别是对于屡次重复执行的查询。Python 的数据库 API 规范建议了 5 种不一样的方式来构造 Prepared Statements,MySQLdb 只支持其中的一种,代码相似于 ANSI printf
的格式化操做。学习
Prepared Statements 在 ORM 库(好比 SQLAlchemy)中应该会有更完善的支持。
注(2016-01-10):
这里的 Prepared Statements 只是客户端的模拟,跟 MySQL Server 的 Prepared Statements 是两码事,因此并不能提升性能或安全性。(详见 C API Prepared Statements)
import MySQLdb as mdb con = mdb.connect('localhost', 'root', '******', 'test') with con: cur = con.cursor() cur.execute("update writers set name = %s where id = %s", ("Guy de Maupasant", "4")) print "Number of rows updated:", cur.rowcount
前面的例子一直使用 with
语句来管理连接 (connection) 对象,避免了 commit
的直接调用。
一旦 cursor 建立,一个事务也就开始,结束时必须调用 commit
或 rollback
。commit
提交修改,rollback
回滚。若是结合 with
语句使用的话,commit
和 rollback
都将自动完成,由于 MySQLdb 的连接对象能够看成 context manager 使用。
# coding: utf-8 import MySQLdb as mdb try: con = mdb.connect('localhost', 'root', '******', 'test') # Cursor 建立,事务开始。 cur = con.cursor() cur.execute('drop table if exists writers') # MyISAM doesn't support transaction. cur.execute('create table writers(id int primary key auto_increment,\ name varchar(25)) engine=innodb') 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")') # 显式地调用 commit 来结束一个事务。 con.commit() except mdb.Error, e: # 异常发生时,调用 rollback 进行回滚。 if con: con.rollback() print "Error %d: %s" % (e.args[0], e.args[1]) sys.exit(1) finally: if con: con.close()
原则上讲,不须要显式地调用 cursor 对象的 close
方法,由于当 cursor 对象生命期结束时,close
方法会被自动调用。源码以下:
class BaseCursor(object): def __del__(self): self.close() self.errorhandler = None self._result = None
不过,仍是建议主动调用 close
,这样至少代码的行为更加明显。