【過期】MySQLdb:Python 操做 MySQL 數據庫

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.數據庫

安裝

經過 pip 安裝

$ apt-get install python-dev libmysqlclient-dev
$ pip install MySQL-python

詳見:How to install Python MySQLdb module using pip?api

經過 apt 安裝

$ sudo apt-get install python-mysqldb

模塊 _mysql

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

使用字典 Cursor

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

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 建立,一個事務也就開始,結束時必須調用 commitrollbackcommit 提交修改,rollback 回滾。若是結合 with 語句使用的話,commitrollback 都將自動完成,由於 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 方法,由於當 cursor 對象生命期結束時,close 方法會被自動調用。源碼以下:

class BaseCursor(object):
    def __del__(self):
        self.close()
        self.errorhandler = None
        self._result = None

不過,仍是建議主動調用 close,這樣至少代碼的行爲更加明顯。

相關文章
相關標籤/搜索