Python操作SQLite/MySQL/LMDB/LevelDB

分享一篇來自簡書的文章,Python操作四種類型的資料庫,各個步驟都有具體代碼貼出來,非常詳細,原文在:Python操作資料庫。

1. 概述

1.1 前言

最近用Caffe跑自己的數據集,需要學習LMDB和LevelDB,趁此機會複習了SQLite和MySQL的使用,一起整理在此。

代碼:https://github.com/liquidconv/py4db

1.2 環境

使用Ubuntu 14.04,Python 2.7.6。

2. SQLite

2.1 準備

SQLite是一種嵌入式資料庫,它的資料庫就是一個文件。Python 2.5x以上版本內置了SQLite3,使用時直接import sqlite3即可。

2.2 操作流程

概括地講,操作SQLite的流程是:

  • 通過sqlite3.open()創建與資料庫文件的連接對象connection;
  • 通過connection.cursor()創建游標對象cursor;
  • 通過cursor.execute()執行SQL語句;
  • 通過connection.commit()提交當前的事務,或者通過cursor.fetchall()獲得查詢結果;
  • 通過connection.close()關閉與資料庫文件的連接。

詳細的sqlite3模塊API可以看這裡:

http://www.runoob.com/sqlite/sqlite-python.html

總結起來就是用cursor.execute()執行SQL語句,改變數據(插入、刪除、修改)時用connection.commit()提交變更,查詢數據時用cursor.fetchall()得到查詢結果。

2.3 操作實例

2.3.1 建立資料庫與建立表

直接來看例子:

#!/usr/bin/env pythonnnimport sqlite3nnconn = sqlite3.connect("test.db");nc = conn.cursor();nc.execute("CREATE TABLE IF NOT EXISTS students (sid INTEGER PRIMARY KEY, name TEXT)");nconn.commit();nconn.close();n

這裡conn是與資料庫文件test.db的連接對象,c是conn的游標對象,通過c.execute()執行建表操作,創建了簡單的學生信息表(學號,名字),通過conn.commit()提交,最後用conn.close()關閉連接。

conn.open()發現文件不存在時會自動創建,這裡使用了文件「test.db」,也可以使用「:memory:」建立內存資料庫。

2.3.2 插入、刪除、修改

為了便於多次運行,直接使用了內存資料庫:

#!/usr/bin/env pythonnnimport sqlite3nnconn = sqlite3.connect(":memory:");nc = conn.cursor();nc.execute("CREATE TABLE students (sid INTEGER PRIMARY KEY, name TEXT)");nconn.commit();nnc.execute("INSERT INTO students VALUES(?, ?)", (1, "Alice"));nc.execute("INSERT INTO students VALUES(?, ?)", (2, "Bob"));nc.execute("INSERT INTO students VALUES(?, ?)", (3, "Peter"));nnc.execute("DELETE FROM students WHERE sid = ?", (1, ));nnc.execute("UPDATE students SET name = ? WHERE sid = ?", ("Mark", 3));nnconn.commit();nconn.close();n

做的事情還是非常簡單易懂的,向學生信息表中插入(1,Alice)、(2,Bob)、(3,Peter)三條記錄,刪除(1,Alice),修改(3,Peter)為(3,Mark)。

「?」是sqlite3中的佔位符,execute時會用第二個參數元組裡的元素按順序替換。官方文檔里建議出於安全考慮,不要直接用python做字元串拼接。

另外注意不需要每次execute後調用commit。

2.3.3 查詢

直接在上面的代碼commit之後加上:

c.execute("SELECT * FROM students");nprint c.fetchall();n

運行一下,輸出結果為:

test_query.py

fetchall()返回的是記錄數組,可以通過WHERE子句做更細緻的選擇。

2.3.4 完整的例子

把上面的操作寫成函數形式:

#!/usr/bin/env pythonn#-*-coding:utf-8 -*-nnimport sqlite3nimport os, sysnndef initialize(conn):n c = conn.cursor();n c.execute("CREATE TABLE students (sid INTEGER PRIMARY KEY, name TEXT)");n conn.commit();nndef insert(conn, sid, name):n c = conn.cursor();n t = (sid, name);n c.execute("INSERT INTO students VALUES (?, ?)", t);n conn.commit();nndef delete(conn, sid):n c = conn.cursor();n t = (sid, );n c.execute("DELETE FROM students WHERE sid = ?", t);n conn.commit();nndef update(conn, sid, name):n c = conn.cursor();n t = (name, sid);n c.execute("UPDATE students SET name = ? WHERE sid = ?", t);n conn.commit();nndef display(conn):n c = conn.cursor();n c.execute("SELECT * FROM students");n print c.fetchall();nndb_name = ":memory:";nconn = sqlite3.connect(db_name);nninitialize(conn);nnprint "Insert 3 records."ninsert(conn, 1, "Alice");ninsert(conn, 2, "Bob");ninsert(conn, 3, "Peter");ndisplay(conn);nnprint "Delete the record where sid = 1."ndelete(conn, 1);ndisplay(conn);nnprint "Update the record where sid = 3."nupdate(conn, 3, "Mark");ndisplay(conn);nnconn.close();n

運行一下,輸出結果為:

test_sqlite.py

之後用的例子都是這個簡單的學生信息表(學號,姓名)。

3. MySQL

3.1 準備

安裝MySQL:

apt-get install mysql-servern apt-get install mysql-clientn apt-get install libmysqlclient-devn

安裝MySQLdb:

apt-get install python-mysqldbn

使用時import MySQLdb(注意大小寫)。

3.2 操作流程

同為關係型資料庫,MySQL的操作方法和SQLite是大同小異的。建立連接對象與游標對象,用execute()執行SQL語句,commi()提交事物,fetchall()獲得查詢結果。

3.3 操作實例

直接看MySQL版本的完整例子:

#!/usr/bin/env pythonn#-*-coding: utf-8-*-nnimport MySQLdbnimport os, sysnndef initialize(conn):n c = conn.cursor();n c.execute(CREATE TABLE IF NOT EXISTS students (n sid INT(4) PRIMARY KEY, name VARCHAR(10)n ));n conn.commit();nndef insert(conn, sid, name):n c = conn.cursor();n t = (sid, name);n c.execute("INSERT INTO students VALUES (%s, %s)", t);n conn.commit();nndef delete(conn, sid):n c = conn.cursor();n t = (sid, );n c.execute("DELETE FROM students WHERE sid = %s", t);n conn.commit();nndef update(conn, sid, name):n c = conn.cursor();n t = (name, sid);n c.execute("UPDATE students SET name = %s WHERE sid = %s", t);n conn.commit();nndef display(conn):n c = conn.cursor();n c.execute("SELECT * FROM students");n print c.fetchall();nntry:n conn = MySQLdb.connect(host = "localhost", user = "root", passwd = "");nexcept Exception, e:n print e;n sys.exit();nnc = conn.cursor();nc.execute("CREATE DATABASE IF NOT EXISTS test");nconn.commit();nconn.select_db("test");nninitialize(conn);nnprint "Insert 3 records."ninsert(conn, 1, "Alice");ninsert(conn, 2, "Bob");ninsert(conn, 3, "Peter");ndisplay(conn);nnprint "Delete the record where sid = 1."ndelete(conn, 1);ndisplay(conn);nnprint "Update the record where sid = 3."nupdate(conn, 3, "Mark");ndisplay(conn);nnc.execute("DROP DATABASE test");nconn.commit();nconn.close();n

對比後可以發現區別僅是建立連接時參數複雜一些,同時需要用select_db()選擇資料庫。

運行一下,輸出結果為:

test_mysql.py

4. LMDB

4.1 準備

學習LMDB的時候不禁想到知乎上的提問「有哪些名人長期生活在其他名人的光環下」,說實話感覺查它的人基本都是為了用Caffe……

Anyway,LMDB和SQLite/MySQL等關係型資料庫不同,屬於key-value資料庫(把LMDB想成dict會比較容易理解),鍵key與值value都是字元串。

安裝:

pip install lmdbn

使用時import lmdb。

4.2 操作流程

概況地講,操作LMDB的流程是:

  • 通過env = lmdb.open()打開環境
  • 通過txn = env.begin()建立事務
  • 通過txn.put(key, value)進行插入和修改
  • 通過txn.delete(key)進行刪除
  • 通過txn.get(key)進行查詢
  • 通過txn.cursor()進行遍歷
  • 通過txn.commit()提交更改

4.3 操作實例

4.3.1 建立環境

#!/usr/bin/env pythonnnimport lmdbnnenv = lmdb.open("students");n

運行一下,查看當前目錄的變化:

set_env.py

可以看到當前目錄下多了students目錄,裡面有data.mdb和lock.mdb兩個文件。

4.3.2 插入、刪除、修改

插入與修改都用put實現,刪除用delete實現。

#!/usr/bin/env pythonnnimport lmdbnnenv = lmdb.open("students");ntxn = env.begin(write = True);nntxn.put(str(1), "Alice");ntxn.put(str(2), "Bob");ntxn.put(str(3), "Peter");nntxn.delete(str(1));nntxn.put(str(3), "Mark");nntxn.commit();n

注意用txn = env.begin()創建事務時,有write = True才能夠寫資料庫。

4.3.3 查詢

查單條記錄用get(key),遍歷資料庫用cursor。

直接在上面的代碼commit()之後加上:

txn = env.begin();nprint txn.get(str(2));nnfor key, value in txn.cursor():n print (key, value);n

運行一下,輸出結果為:

test_query.py

注意上次commit()之後要用env.begin()更新txn。

4.3.4 完整的例子

#!/usr/bin/env pythonnnimport lmdbnimport os, sysnndef initialize():n env = lmdb.open("students");n return env;nndef insert(env, sid, name):n txn = env.begin(write = True);n txn.put(str(sid), name);n txn.commit();nndef delete(env, sid):n txn = env.begin(write = True);n txn.delete(str(sid));n txn.commit();nndef update(env, sid, name):n txn = env.begin(write = True);n txn.put(str(sid), name);n txn.commit();nndef search(env, sid):n txn = env.begin();n name = txn.get(str(sid));n return name;nndef display(env):n txn = env.begin();n cur = txn.cursor();n for key, value in cur:n print (key, value);nnenv = initialize();nnprint "Insert 3 records."ninsert(env, 1, "Alice");ninsert(env, 2, "Bob");ninsert(env, 3, "Peter");ndisplay(env);nnprint "Delete the record where sid = 1."ndelete(env, 1);ndisplay(env);nnprint "Update the record where sid = 3."nupdate(env, 3, "Mark");ndisplay(env);nnprint "Get the name of student whose sid = 3."nname = search(env, 3);nprint name;nnenv.close();nnos.system("rm -r students");n

運行一下,輸出結果為:

test_lmdb.py

5. LevelDB

5.1 準備

同為key-value資料庫,LevelDB的資料比LMDB豐富太多了。值得一提的是LevelDB實現時用到了SkipList,以後有機會要親自實現一下。

安裝:

pip install py-leveldbn

使用時import leveldb。

5.2 操作流程

LevelDB操作時類似與LMDB,使用Put/Get/Delete,但是更加簡單(不需要事務txn和commit提交),同時支持範圍迭代器RangeIter。

5.3 操作實例

來看LevelDB版本的完整例子:

#!/usr/bin/env pythonn#-*-coding: utf-8-*-nnimport leveldbnimport os, sysnndef initialize():n db = leveldb.LevelDB("students");n return db;nndef insert(db, sid, name):n db.Put(str(sid), name);nndef delete(db, sid):n db.Delete(str(sid));nndef update(db, sid, name):n db.Put(str(sid), name);nndef search(db, sid):n name = db.Get(str(sid));n return name;nndef display(db):n for key, value in db.RangeIter():n print (key, value);nndb = initialize();nnprint "Insert 3 records."ninsert(db, 1, "Alice");ninsert(db, 2, "Bob");ninsert(db, 3, "Peter");ndisplay(db);nnprint "Delete the record where sid = 1."ndelete(db, 1);ndisplay(db);nnprint "Update the record where sid = 3."nupdate(db, 3, "Mark");ndisplay(db);nnprint "Get the name of student whose sid = 3."nname = search(db, 3);nprint name;nnos.system("rm -r students");n

運行一下,輸出結果為:

test_leveldb.py

此外,由於沒有commit()操作,leveldb中用WriteBatch實現多條更改一次提交,直接copy示例代碼如下:

batch = leveldb.WriteBatch();nbatch.Put(hello, world);nbatch.Put(hello again, world);nbatch.Delete(hello);ndb.Write(batch, sync = True);n

6. 學習總結

這次學習四種資料庫操作時,是按照SQLite -> MySQL -> LMDB -> LevelDB的順序,所以研究SQLite與LMDB花了較長時間,而MySQL與LevelDB很快就搞定了。某種意義上,學習技術和背單詞一樣,當前掌握的單詞越多,背新單詞就越容易——因為可以把新單詞和已經掌握的同義詞聯繫在一起,在腦海里聚成簇。

最後回顧一下,SQLite與MySQL都是關係型資料庫,操作時創建連接對象connection與游標對象cursor,通過execute執行SQL語句,commit提交變更,fetch得到查詢結果;LMDB與LevelDB都是K-V資料庫,操作時建立與資料庫的連接,用put/delete改變數據,用get獲取數據,區別是LMDB中有事務需要commit,LevelDB不需要。

7. 參考資料

  • SQLite
    • SQLite教程:

      http://www.runoob.com/sqlite/sqlite-python.html
    • SQLite全面學習:

      http://blog.jobbole.com/92796/
    • Python文檔關於sqlite3的介紹:

      https://docs.python.org/2/library/sqlite3.html
  • MySQL
    • MySQLdb模塊:

      http://www.oschina.net/code/snippet_16840_1811

    • Python操作MySQL:

      http://www.cnblogs.com/rollenholt/archive/2012/05/29/2524327.html
  • LMDB
    • Creating an LMDB database in Python:

      http://deepdish.io/2015/04/28/creating-lmdb-in-python/
    • Python lmdb:

      http://blog.csdn.net/ayst123/article/details/44077903
    • lmdb 0.87 documentation:

      http://lmdb.readthedocs.org/en/latest/
  • LevelDB
    • py-leveldb示例代碼:

      http://www.oschina.net/p/py-leveldb?fromerr=G5QJs7l1
    • Having a look at LevelDB:

      http://skipperkongen.dk/2013/02/14/having-a-look-at-leveldb/

我的公眾號,有興趣的小夥伴可以關注下:

weixin.qq.com/r/AykDG7r (二維碼自動識別)


推薦閱讀:

讓彈幕飄一會兒的Python小實驗
Python學習如何下手?看完本文後你能明白60%
17個新手常見Python運行時錯誤
Python從零開始系列連載(3)——jupyter的常用操作(中)
Python從零開始系列連載(19)——Python特色數據類型(列表)(下)

TAG:Python | Python教程 |