任務
你想將一些數據做持久化處理,而且也想體驗一下BerkeleyDB數據庫的簡潔和高效。
解決方案
如果以前在你的計算機中安裝過 BerkeleyDB,Python標準庫附帶的bsddb包(以及可選的 bsddb3,用于訪間Berkeley DBrelease 3.2數據庫)可以被用來作為 Berkeley DB接口。為了得到 bsddb 或者 bsddb3,如果沒有bsddb 的話,應當在 import 聲明的時候使用 try/exception:
try:from bsddb import db#先試試release 4
except ImportError:from bsddb3 import db#沒有,再試試release 3
print db.DB_VERSION_STRING
#輸出,示例:sleepycat Software:Berkeley DB 4.1.25:(December 19,2002)
為了創建一個數據庫,我們要初始化一個 db.DB 對象,然后向它的 open方法傳入適當的參數并調用之,如下:
adb = db.DB()
adb.open('db_filename', dbtype = db.DB_HASH, flags = db.DB_CREATE)
當你想創建一個數據庫時,db.DB_HASH 是幾種可以選擇的訪問方法中的一種,一個很常見的選擇是 db.DB_BTREE,使用 B+樹訪問(如果你想以排序的方式獲取記錄,這很方便)。也可以選擇構建一個內存數據庫,不使用任何持久化文件,只要將None作為文件名和第一個參數傳遞給 open 方法即可。
一旦有了一個打開的 db.DB 實例,你就可以添加記錄了。每條記錄由兩個字符串構成鍵和數據:
for i,w in enumerate('some words for example'.split( )):adb.put(w,str(i))
可以通過數據庫的游標訪問記錄:
def irecords(curs):record = curs.first()while record:yield recordrecord = curs.next()
for key,data in irecords(adb.cursor()):print 'key = %r,data = %r' %(key,data)
#輸出(the order may vary):
# key = 'some', data = '0'
# key = 'example', data = '3'
# key = 'words', data = '1'
# key = 'for', data = '2'
做完之后,需要關閉數據庫:
adb.close()
以后,在同一個或其他的Python程序中,可以給新創建的db.DB 實例的open 方法傳遞同樣的文件名,再次打開該數據庫:
the_same_db = db.DB()
the_same_db.open('db_filename')
然后用同樣的方式繼續工作:
the_same_db.put('skidoo',23')#添加一條記錄
the_same_db.put('words','sweet')#替換一條記錄
for key,data in irecords(the_same_db.cursor()):print 'key=%r,data=%r'%(key,data)
#輸出(the order may vary):
# key='some',data='0'
# key='example',data='3'
# key='words',data='sweet'
# key='for',data='2'
# key='skidoo',data='23'
再次提醒,在所有操作結束之后不要忘記關閉數據庫:
the_same_db.close()
討論
Berkeley DB 是一個流行的開源數據庫。它不支持SQL,但卻很容易使用,并提供了優異的性能,如果你希望掌控全局的話,它給了你充分的自由來控制所發生的一切,可以通過大量的選項、標志以及方法來完成控制。除了Python,我們也可以通過其他語言來訪問 Berkeley DB:比如,可以用 Python 程序完成一些修改和查詢,然后再使用一個獨立的C程序,使用相同的基本開源庫(可以從Sleepycat 下載),對同樣的數據庫做同樣的事情。
Python 標準庫模塊shelve 可以使用 Berkeley DB 作為它的數據庫引擎,就像它使用cPickle 進行序列化操作一樣。然而,如果記錄都是由 pickle.dumps 產生的串,而這些串對于除 Python 之外的任何語言來說都是很難處理的數據,那你將無法用其他語言訪問Berkeley DB數據庫文件。通過bsddb直接訪問 Berkeley DB,數據庫引擎能夠提供很多高級的功能,而這些都是 shelve無法提供的。
數據庫還是 pickle,或者兩者都用?
pickle 和 marshal,以及數據庫系統如 Berkeley DB 或關系型數據庫,它們的應用場合有很大不同,但是仍然有一些重疊的地方
pickle(以及 marshal)本質上是序列化處理:將Python 對象轉變成可以傳輸或者儲存的 BLOB,之后可以由另一方接收或者恢復。序列化的數據是被用來重建Pythor對象的,基本上也只能被 Python 應用程序訪問。而針對對象或對象的一部分的搜索和選擇操作,pickle 不能提供任何支持
數據庫(Berkeley DB,關系型數據庫,以及其他類型)本質上是以數據為核心的:可以保存或者獲取成組的基本類型的數據(大多是字符串和數字),還能夠得到很多有關選取和搜索(對于關系型數據,這種支持可以說是海量的)以及跨語言的支持。數據庫對于將 Python 對象序列化成數據或者從數據中反序列化出Python 對象一無所知。
數據庫和序列化這兩種方式也可以被混用。可以用 pickle 將 Python 對象序列化成字節碼,然后用數據庫儲存,或者反過來。但 Python 標準庫 shelve 模塊只是在一個很底層的層面工作,比如,它可以借助 pickle 來完成序列化和反序列化,或使用bsddb來作為底層的數據庫引擎。因此,不要認為兩種方式是一種“競爭的”關系——而應該認為兩者是一種互相補充的關系。
舉個例子,如解決方案中的代碼所示,創建一個帶有db.DB_HASH 訪間方式的數據庫我們可以獲得最大的效率,不過,你可能也注意到了,用生成器irecords 列出所有的記錄時,哈希算法使得記錄以一種隨機的和無法預測的順序排列。如果你想以一種排序的方式訪問記錄,應該使用 db.DB_BTREE方法。BerkeleyDB支持很多高級功能,如事務,可以直接訪問數據庫來獲得這種功能,而不是試圖通過anydbm 或者shelve 來訪問。
更多的關于 Python 標準庫 bsddb 包的詳細文檔,請參看 http://pybsddb.sourceforge.netbsddb3.html。而關于BerkeleyDB本身的文檔、下載以及其他資料,請訪問http://www.sleepycat.com。