sqlite 和berkeley db 的效能比較

NO IMAGE

嵌入式資料庫典型技術―SQLite和Berkeley DB的研究

摘要:與常見的資料庫相比,嵌入式資料庫具有體積小、功能齊備、可移植性、健壯性等特點,本文分析和比較了典型的嵌入式資料庫SQLite和Berkeley DB。首先從體系結構、子系統間呼叫關係、任務執行過程等角度對SQLite和Berkeley
DB進行了詳細分析,然後重點從資料型別、儲存方式、模式、資料庫引擎和錯誤處理及加密功能等方面討論了SQLite和Berkeley DB的異同點,最後列舉了一個基於ARM—Linux的SQLite應用例項。

 

關鍵詞: SQLite、Berkeley DB、SQL、虛擬資料庫引擎(VDBE)

 

引言

隨著計算機技術與其它學科間的不斷交融、滲透,資料庫應用的範圍更加深入和具體。那些僅適用於PC機,體積龐大、延時較長的資料庫技術已不能滿足針對性較強的嵌入式系統開發的需求。SOLite和Berkeley DB是目前應用較廣泛、技術較穩定的兩種嵌入式資料庫。然而,國內對嵌入式資料庫的研究起步較晚,還沒能引起更多人的關注。更多人熟悉那些基於C/S或B/S結構的關係型資料庫來實現資料的儲存、檢索等功能。然而,在嵌入式系統中,由於軟硬體資源有限,不可能安裝龐大的資料庫伺服器,而使用者的需求可能由一個簡單的基於磁碟檔案的資料庫系統就能實現,這僅僅是利用了那些資料庫的基本特性。此時,對嵌入式資料庫的研究就顯得尤為重要了。

 

一、嵌入式資料庫

嵌入式資料庫通常是與嵌入式作業系統及具體的應用整合在一起,無需獨立執行資料庫引擎,由程式直接呼叫相應的API就可實現對資料的存取操作。嵌入式系統的開發環境決定了其資料庫的特點:

1、體積適當

由於嵌入式系統自身的特點,對資料的儲存和程式的執行都有較強的空間限制,所以嵌入式資料庫首先應該保障的就是適當的體積。進一步來說就是佔用儘量少的ROM、RAM及CPU的資源。

2、功能齊備

嵌入式系統開發中,使用者需求決定了需要一個大小適中、功能齊備的資料庫來實現資料管理,這就使得開發人員要採用一個能夠提供完備開發文件且易於開發的資料庫技術。此外,國家863專案2002AA714023,研究生精品課程資助05531451在嵌入式裝置中,資料庫的管理對使用者來說是透明的,這就要求此資料庫能夠自動完成啟動初始化、日誌管理、資料壓縮、備份、資料恢復等功能;而且嵌入式裝置經常有不可預料的硬復位,這就需要此資料庫有高度的健壯性。

3、可移植性

嵌入式系統的平臺種類繁多,因此嵌入式資料庫應有一定的可移植性,以適用於不同的軟硬體平臺。

4、程式碼開源

開源的程式碼在產品的開發過程中不僅可以減少開發成本,更重要的是為後期的維護完善和穩定執行都提供了最為徹底的解決方法。

 

二、SQLite

SQLite是D.理查德.希普用一個小型的C庫開發的一種強有力的嵌入式關聯式資料庫管理體制。雖然功能較Berkeley
DB稍顯遜色,但它簡單易學、速度較快,同時提供了豐富的資料庫介面,提供了對SQL92的大多數支援:支援多表和索引、事務、檢視、觸發和一系列的使用者介面及驅動。

SQLite和Berkeley DB(BDB)比較資料收集 - lanhy2000 - 不當老闆

圖1 SQLite的體系結構

 

SQLite的體系結構大體上可以分成八個主要的子系統,如圖1所示。對資料庫進行的各種操作都是按照此順序,逐一執行的。頂層是標記處理器(tokenize)和分析器(parser)。SQLite有自己高度優化的程式碼生成器,可以快速、高效地生產出程式碼。底部是經過優化的B樹,這樣有助於執行在可調整的頁面緩衝上時,對磁碟的查詢降低到最小。再往下是頁面快取記憶體,它作用在OS的抽象層之上,這樣的體系結構使資料庫的可移植性變為可能。

該體系結構的核心是虛擬資料庫引擎(VDBE)。VDBE完成與資料操作相關的全部任務,並且是客戶和儲存之間資訊交換的中間單元。從各個角度分析,它都是SQLite的核心。當SQL語句被分析後,VDBE便開始工作。程式碼生成器將分析樹翻譯成一個袖珍程式,隨後這些袖珍程式又被組合成VDBE的虛擬機器器語言表示的一系列指令。如此反覆,VDBE執行每條指令,最終完成SQL語句指定的查詢要求。

SQLite有以下特性:支援ACID事務、零配置―無需安裝和管理配置、儲存在單一磁碟檔案中的一個完整的資料庫、資料庫檔案可以在不同位元組順序的機器間自由共享、支援資料庫大小至2TB、足夠小、全部原始碼大致3萬行C程式碼,250KB、比目前流行的大多資料庫執行速度快,提供了對事務功能和併發處理的支援、應用Transaction既保證了資料的完整性,也會提高執行速度,因為多條語句一起提交給資料庫的速度會比逐一提交的方式更快、獨立、沒有額外依賴。

 

三、Berkeley DB

Berkeley DB是由sleepycat software開發的輕量級嵌入式資料庫,它不僅適用於嵌入式系統,而且可以直接連線到應用程式內部,和應用程式執行在同一地址空間。傳統的資料庫一般作為獨立伺服器工作,而Berkeley
DB是軟體開發庫,開發者將它嵌入到應用程式中,應用程式本身就是一個伺服器,而只是利用嵌入式資料庫開發來實現定製的資料庫邏輯,避免了與應用伺服器程序間通訊的開銷,因此Berkeley DB具有較高的執行效率,適用於資源受限的嵌入式系統。

一般而言,Berkeley DB資料庫系統可以大致分為五個子系統,如圖2所示。

SQLite和Berkeley DB(BDB)比較資料收集 - lanhy2000 - 不當老闆

圖2  Berkeley DB
子系統圖

1、存取管理子系統(Access Methods)

該子系統為建立和訪問資料庫檔案提供基本的支援。在沒有事務管理的情況下,該子系統中的模組可單獨使用,為應用程式提供快速高效的資料存取服務。

2、記憶體池管理子系統(Memory Pool)

該子系統就是Berkeley DB所使用的通用共享記憶體緩衝區,該子系統可以被應用程式單獨使用。

3、事務子系統(Transaction)

該子系統為Berkekey DB提供事務管理功能,保證操作的原則性、一致性和孤立性。事務子系統適用於對需要事務保證的資料進行修改的場合。

4、鎖子系統(Locking)

       該子系統提供程序之間以及程序內部的併發管理機制,為系統提供多使用者讀取和單使用者修改同一物件的共享控制。該子系統可以被應用程式單獨使用。

5、日誌子系統(Logging)

該子系統採用的是先寫日誌的策略,支援事務子系統進行資料恢復,保證資料一致性。

四、SQLite與Berkeley DB的異同

 

   通過上面的一些介紹,也許會對SQLite和Berkeley DB有了一定的瞭解。從目前的趨勢看,這兩款嵌入式資料庫有著旺盛的生命力,較好的應用領域及發展空間。筆者翻閱了大量的資料,從各個角度,對它們的異同進行了多方面,多層次的比較,如表1所示。

 

表1 SQLite與Berkeley DB的異同

特性

SQLite

Berkeley DB

是否為關聯式資料庫

是否支援SQL

開發語言

C語言

C、Java語言

資料型別

儲存方式

轉換成ASCII碼

原樣儲存

儲存模式

Btree

Btree、Hash、Queue和Recno

資料庫引擎

虛擬

適用系統

從ARM/Linux到SPARC/Solaris多種硬體平臺

UNIX/POSIX systems、Win32及嵌入式系統WinCE、VxWorks等

錯誤處理

較少

較詳細

加密功能

是否免費

全部

部分

難易程度

較易

較難

 

通過此表我們可以較為直觀地看到,SQLite和Berkeley DB在資料庫型別、開發語言、儲存方式、模式等方面有著較大的差異。下面筆者就對其中某些重要方面進行相對詳細的論述:

1、資料庫型別

SQLite基於關聯式資料庫模式,支援絕大多數標準的SQL92語句,在很大程度上實現了ANSI SQL92標準,特別是支援檢視、觸發器、事務,支援巢狀SQL。它通過SQL編譯器(SQL
Complier)來實現SQL語言對資料庫進行操作,採用單檔案存放資料庫。在操作語句上更類似關係型資料庫的產品使用,非常方便。這也就使得那些曾經有過PC機資料庫經驗的人,對SQLite的學習變得易如反掌。

此外,SQLite也有API的概念,而且極其易於使用,只需要三個用來執行SQL和獲得資料的函式。它還是可以擴充套件的,允許程式設計師自定義函式,然後以callback的形式集合進去。C語言API是指令碼介面的基礎,如已經發布的(Tcl介面)。開放原始碼團體已經擴充套件了眾多的客戶介面、介面卡、驅動等,這就使得其他語言對SQLite的使用也成為可能。

Berkeley DB不是關係型的資料庫,不能應用標準的SQL語句對資料庫操作,對它的操作要呼叫專用的API實現。這些API提供了查詢、插入、刪除等功能。使用Berkeley
DB提供的函式來進行資料庫的訪問和管理並不複雜。在大多數場合下,只需按照統一的介面標準進行呼叫就可以完成最基本的操作。

2、儲存方式及模式

SQLite只提供了Btree儲存資料的模式。對二進位制資料,SQLite不能直接儲存;但可以先將二進位制的資料轉換成ASCII編碼,然後再儲存。Base64編碼機制是最常見的把二進位制資料轉換成ASCII編碼的手段。在SQLite的C語言程式碼encode.c中,提供了Base64編碼的功能。

Berkeley DB對任何存入的資料都是按原樣直接儲存到資料檔案中去,無論其是二進位制資料還是ASCII或Unicode等編碼的文字。Berkeley
DB提供了四種儲存資料的模式:Btree、Hash、Queue和Recno。在開啟資料庫的時候,要指定一種儲存模式。

對於以上各種儲存模式的具體定義、優缺點、及適用範圍,由於篇幅有限,在此就不過多敘述,如有需要可參閱相關資料。

3、資料型別

SQLite最大的特點在於其資料型別為無資料型別(typelessness)。這意味著可以儲存任何型別的資料到所想要儲存的任何表的任何列中,無論這列宣告的資料型別是什麼。雖然在生成表結構的時候,要宣告每個域的資料型別,但SQLite並不做任何檢查。開發人員要靠自己的程式來控制輸入與讀出資料的型別。這裡有一個例外,就是當主鍵為整型值時,如果要插入一個非整型值時會產生異常。

雖然,SQLite允許忽略資料型別,但是,仍然建議在Create Table語句中指定資料型別,因為資料型別有利於增強程式的可讀性。另外,雖然在插入或讀出資料的時候是不區分型別的,但在比較的時候,不同資料型別是有區別的。

在Berkeley DB中關鍵字(key)和資料(data)是用來進行資料庫管理的基礎,由這兩者構成的key/data對,組成了資料庫中的一個基本結構單元。通過使用這種方式,用API函式訪問資料庫時,只需提供關鍵字就能夠訪問到相應的資料。關鍵字和資料在Berkeley
DB中都是用一個名為DBT的簡單結構來表示的,它的作用主要是儲存相應的記憶體地址及其長度。

五、 應用

SQLite嵌入式資料庫提供了以原始碼釋出的方式,要在眾多的硬體平臺進行移植,可以根據不同平臺對原始碼進行交叉編譯來實現。編譯主要有以下幾個步驟:

1、到http://www.sqlite.org/的cvs中下載最新的原始碼包,解壓後將生成sqlite目錄,另外新建並轉到一個與sqlite目錄平行的同級目錄,如make目錄。

2、用“echo$PATH”命令檢視PATH中是否已經包含交叉編譯工具arm-linux-gcc。

3、為了在ARM-Linux下能正常執行sqlite,需要對sqlite/src/sqliteInt.h作一定的修改,以確保btree(B樹)有正確的變數大小,如“ptr”和“char”。不同體系結構的Linux,如X86和ARM,會有些差別。對於ARM-Linux可以找到如下部分:

# ifndef INTPTR_TYPE

# if SQLITE_PTR_SZ==4

# define INTPTR_TYPE int

# else

# define INTPTR_TYPE long long

# endif

在上面的程式碼前加上一句

# define SQLITE_PTR_SZ 4

這樣後面的“typedef INTPTR_TYPE ptr;”就是定義的“int”型別,而不是“long long”。

4、使用configure進行一些配置。修改sqlite目錄下的configure,讓configure不去檢查交叉編譯環境。由於篇幅有限不再詳述。

       5、修改Makefile檔案。將程式碼行BCC=arm-linux-gcc-g-O2改成BCC=gcc-g-O2。另外,一般是以靜態連結的形式將sqlite放到ARM-Linux的硬體板上執行的,所以繼續修改Makefile,找到標記為sqlite:的程式碼段,將其中的libsqlite.la改成.libs/libsqlite.a。做完上述修改,用make生成sqlite、libsqlite.a、libsqlite.so。為了減小執行檔案大小可以用strip處理,去掉其中的除錯資訊。

       6、在ARM板上執行sqlite。將sqlite拷貝到ARM板上,方法很多,需要根據具體的情況來選擇。如ftp、cm-dftp、wget等。將sqlite下載到ARM板的/tmp目錄,因為此目錄是可寫的。修改許可權並執行:

chmod wx sqlite

./sqlite test.sqlite

會出現

       sqlite>

如果一切正常,現在sqlite已經在ARM-Linux下跑了起來,然後就可以基於此進行下一步的應用開發了。

六、結語

嵌入式資料庫SQLite和Berkeley DB,在體積上、功能上、執行速度及難易程度都存在著或多或少的異同。但它們都有能夠充分適應硬體的能力,能很好地適應嵌入式系統的需要。就筆者來看,SQLite功能雖不及Berkeley
DB強大,但它的設計思想是小型、快速和最小化的管理。這就使得SQLite在大小和功能之間找到了一個理想的平衡點,而且完全的開原始碼使其可以稱得上是理想的“嵌入式資料庫”。當然在具體的嵌入式應用中可以根據具體情況選擇應用。

 

參考文獻:

1、http://www.sqlite.org
, SQLite的官方主頁

2、http://www.sleepycat.com
,Berkeley DB的官方主頁

3、Michael Owens. Embedding an SQL Database with Sqlite. Linux Journal,2003 06 01

4、薛啟康.Linux環境下的資料庫.中國計算機報,2001總期號:1009

5、張孝.嵌入式移動資料庫的現狀及發展[J/OL].
http://www.basesoft.com

 

免費的實時資料庫,我們該選誰?—-BerkeleyDB與SQLite評測對比

http://blog.csdn.net/mynicedream

最近要做一個專案,需要用到實時資料庫,PI太貴了,想找一個免費的,實在不行就只能自己編了。找了半天,找到了FastDB、BerkeleyDB和SQLite.

FastDB是記憶體型資料庫,據說很快,但資料庫大小不能大於實體記憶體,不然。。。反正我看到這就走了,我可是要一秒內處理幾千個資料,還要儲存8小時以上的啊!BerkeleyDB和SQLite倒沒有資料庫大小不能大於實體記憶體的限制,我對他們的效能進行了測試,結果如下:

 操作

Berkeley DB

Sqlite

插入10000條記錄耗時

0.08秒

0.42秒

插入100000條記錄耗時

2.31秒

3.81秒

插入7200000條記錄耗時

1024.34秒

249秒

插入57600000條記錄耗時

12860.78秒

2155.14秒

插入172800000條記錄耗時

48039.64秒

6352.06秒

10000條記錄查1記錄耗時

少於0.01秒

少於0.01秒

100000條記錄查1記錄耗時

少於0.01秒

少於0.01秒

7200000條記錄查1記錄耗時

少於0.01秒

少於0.01秒

57600000條記錄查1記錄耗時

0.03秒

0.16秒

172800000條記錄查1記錄耗時

0.03秒

0.09秒

10000條記錄資料庫大小

0.628M

0.527M

100000條記錄資料庫大小

5.29M

5.32M

7200000條記錄資料庫大小

516M

405M

57600000條記錄資料庫大小

3087.13M

3925.8M

172800000條記錄資料庫大小

11890.7M

10621.2M

*機器配置:Core2 E4500CPU、2G記憶體

上表為兩種資料庫只建一個索引,Berkeley DB不支援事務、Sqlite支援事務情況下的資料,如果Berkeley
DB開啟事務支援,速度會下降很大的數量級,根本不能滿足需求。另外在程式崩潰後Berkeley DB資料庫不可用,Sqlite資料庫仍可正常使用。

 

Berkeley DB與Sqlite對比

嵌入式資料庫無需安裝,體積小巧,速度又很快,在很多場合可以替代目前流行的MySQL, SQLServer等大中型資料庫。本文介紹兩種嵌入式資料庫產品:Berkeley DB和SQLite,並著重討論它們與Java之間的介面。

通常我們採用各種資料庫產品來實現對資料的儲存、檢索等功能,例如,Oracle,SQL Server,MySQL等等。這些產品除提供基本的查詢,刪除,新增等功能外,也提供了很多高階特性,如觸發器,儲存過程,資料備份恢復,全文檢索功能等。但實際上,很多的應用,僅僅利用到了這些資料庫產品的基本特性而已。而且在一些小型應用上,或者某些特殊場合的應用,比如桌面程式,這些資料庫產品就明顯有一些臃腫。在這些情況下,嵌入式資料庫的優勢就特別明顯了。

嵌入式資料庫無須獨立執行的資料庫引擎,它是由程式直接呼叫相應的API去實現對資料的存取操作。更直白的講,嵌入式資料庫是一種具備了基本資料庫特性的資料檔案。嵌入式資料庫與其它資料庫產品的區別是,前者是程式驅動式,
而後者是引擎響應式。嵌入式資料庫的一個很重要的特點是它們的體積非常小,編譯後的產品也不過幾十K。這不但對桌面程式的資料儲存方案是一個很好的選擇,也使得它們可以應用到一些移動裝置上。同時,很多嵌入式資料庫在效能上也優於其它資料庫,所以在高效能的應用上也常見嵌入式資料庫的身影。

下面介紹的是兩個開放原始碼的嵌入式資料庫,Berkeley DB和SQLite。同時側重介紹如何應用Java連線這兩種嵌入式資料庫。

一. Berkeley DB

1. 簡介

Berkeley DB是一款健壯的,高速的工業級嵌入式資料庫產品,你可以在它的官方主頁(見參考連結一)上發現很多知名的公司都採用了這款嵌入式資料庫。 Berkeley DB的一個很重要的特點是就是高速儲存。在高流量,高併發的情況下,Berkeley
DB要比非嵌入式的資料庫表現得更加出色。所以在一些技術實現上,Berkeley DB被作為大型關聯式資料庫的中間資料緩衝層,用來快速的儲存資料,可能會在適當的時刻再匯入到大型資料庫中,進而應用大型資料庫所提供的更為高階的特性。

Berkeley DB雖然是開源的產品,但對某些條件下的商業性應用,卻不是免費的,而且價格頗為昂貴。這些商業條件排除了開源的情況,不發放分佈版本的情況,等等。比如,如果你的程式是開放原始碼的或者僅僅應用到單一的網站上,在這種情況下,Berkeley DB是免費的。

2. 獲得Java與Berkeley DB的介面

Berkeley DB目前的版本是4.1.25,自帶了Java介面。下載的壓縮包中包含C和Java語言的原始碼和編譯配置檔案。在Windows平臺,可以用MS
Visual C 6.0或MS VC.Net編譯。用VC6編譯的操作如下介紹:在原始碼的build_win32路徑下開啟VC的工程檔案,之後在Build選單中的Set
Active Configuration選擇db_java win32 release編譯選項。在VC的Tools選單Options選項中指定JNI.H等Java本地化介面編譯時所需要標頭檔案的位置。你會在JDK的
include路徑下找到這些標頭檔案, 例如加入的路徑可能會是這樣的:C:\jdk1.4\include和C:\jdk1.4\include\ win32。最後在Tools選單中Options選項還要設定Javac.exe和Jar.exe的執行路徑,這個設定會使VC開發環境也能呼叫
Java編譯器,從而在VC環境下直接完成對Java介面類的編譯和打包。在編譯後,在release路徑下的檔案中找到db.jar,
libdb41.dll, libdb_java41.dll,這三個檔案組成了Berkeley DB的Java介面程式包。

3. 應用Java與Berkeley DB的介面

Berkeley DB並不是一個關係型的資料庫。不能應用標準的SQL語句對資料庫操作,對它的操作要呼叫專用的API實現。這些API提供了查詢、插入、刪除等功能。比如com.sleepycat.db.Db類代表資料庫物件。Db類的put()方法完成的是插入功能,get()方法完成的是讀出資料的功能。
com.sleepycat.db.Dbc是Berkeley DB的遊標類,提供了遍歷資料庫記錄的功能。

Berkeley DB每一個記錄都有一個鍵值和對應的資料值,而鍵值和資料必須是類com.sleepycat.db.Dbt的物件或其子類的物件。Dbt提供了一些方法可以將byte陣列或Object物件儲存到Dbt的物件中去。比如,Dbt類中的set_data(byte[])或set_object
(Object)方法。注意到目前Berkeley DB中的Java API命名方法並不符合Java的命名規範,比如set_data()方法應該命名為setData()方法。Berkeley
DB許諾在下一個版本中會提供符合命名規範的Java API。

Berkeley DB對任何存入的資料都是直接原樣儲存到資料檔案中去,無論其是二進位制資料還是ASCII或Unicode等編碼的文字。通常可以利用這一特性和Java序列化的概念方便的進行資料的存取。例如宣告一個類

public class AccountInfo implements Serializable{

//帳戶資訊

public String loginName;

public String password;

public boolean auotLogin;

}

在這個 AccountInfo類中僅僅包含了資料項的定義。我們完全可以將這個類看作資料庫的表中欄位定義。可以用Berkeley DB儲存AccountInfo物件的序列化二進位制資料,以此來儲存這個物件中的變數值。在操作中,先對Dbt的物件呼叫set_object
(AccountInfo)方法,而後把這個Dbt物件作為一條紀錄儲存到表中。當然,我們也可以應用繼承Dbt類的方法來完成對資料的儲存。

下面這段簡單程式碼演示如何將資料存入到資料庫中,然後再用遊標物件瀏覽全部資料。

 

//注意,下面的程式的忽略了對異常處理,寫入資料初始化等等一些程式碼,請在適當修改後再編

//譯執行它

Db dbFile = null;

//生成Db物件

dbFile = new Db(null, 0);

//用BTree方式開啟資料庫,庫檔案是在c:/temp下的mydata.db檔案,表名是employee

//如果資料庫不存在,則自動生成一個新的資料庫。

dbFile.open(null,”c:\\temp\\mydata.db”,”employee”,Db.DB_BTREE,

Db.DB_CREATE,0);

Dbt key = new Dbt();

Dbt data = new Dbt();

//向庫檔案中插入一條資料,如果已經存在,列印出錯資訊

if (dbFile.put(null,key, data, Db.DB_APPEND) == Db.DB_KEYEXIST) {

System.out.println(“Key already exists.”);

}

//關閉資料檔案

dbFile.close(0);

//重新開啟資料檔案

dbFile = new Db(null, 0);

dbFile.open(null, “c:\\temp\\mydata.db”, “employee”, Db.DB_UNKNOWN,

0, 0644);

// 宣告一個資料庫遊標Dbc物件iterator

Dbc iterator = dbFile.cursor(null, 0);

// 遍歷整個表

Dbt key = new Dbt();

while (iterator.get(key, data, Db.DB_NEXT) == 0)

{

System.out.println(“reading”);

}

//關閉遊標和資料檔案

iterator.close();

dbFile.close(0);

 

在執行Berkeley DB的程式時勿必在系統環境變數PATH中設定libdb41.dll和 libdb_java41.dll所在的路徑。

4. Berkeley DB的儲存模式

Berkeley DB提供了四種儲存資料的模式:Btree,Hash,Queue和Recno。在開啟資料庫的時候要指定一種儲存模式,比如上例中open()方法中的引數Db.DB_BTREE就是指定以Btree模式開啟資料庫。

Btree模式是以排序的二叉樹的方式儲存,Hash是以線性雜湊表的方式儲存。Queue用邏輯記錄號做為鍵值,以定長的資料為記錄值。Recno方式也以邏輯記錄號做為鍵值,但可以儲存定長或變長的記錄值。這裡提到的邏輯記錄號有兩種,可變的和固定的。可變邏輯記錄號會根據資料記錄的增加與刪除做相應的變化。比如在資料庫中共有100條記錄,如果刪除第80條記錄,那麼第81條記錄的邏輯記錄號會自動變成80,以此類推,第100條記錄邏輯記錄號會變成99。固定的邏輯記錄號則無論資料庫如何操作都不會有變化。Queue模式下,邏輯記錄號只能是固定方式。
Recno模式則可通過配置來選擇是採用那種型別的記錄號作為鍵值。Btree模式也可以通過設定,將可變的邏輯記錄號做為鍵值。

這幾種儲存模式各有優缺點,要根據具體的需求來選擇。當鍵值不想用邏輯記錄號時Btree或Hash是必須的選擇。 Btree方式比較適合連續的順序讀取,比如,當鍵值是時間值,如果經常有從某一時間點開始連續讀取後繼的記錄的操作,Btree是一種很好的選擇。對隨機的跳躍式讀取,Hash模式則更為恰當。Queue和Recno都以記錄號為鍵值,但前者適合先進先出的讀取方式。Recno則通常是存取變長文字記錄的理想儲存模式。

5. Berkeley DB Environment的概念

Berkeley DB Environment為一組資料庫同時提供引數設定。更為重要的是,如果要應用更高階的特性,必須要使用Environment功能,比如在想要對儲存的資料進行加密儲存時。

6. 更多特點

除了最基本的插入、查詢、刪除功能以外,Berkeley DB還提供了一些特性,比如Transaction,資料加密,同步加鎖控制,錯誤日誌等功能。下面的圖片是Berkeley DB功能示意圖。

二. SQLite

1. 簡介

相信PHP的開發人員一定不會對SQLite感到陌生,因為在PHP5中已經整合了這個輕巧的內嵌式資料庫產品。SQLite與Berkeley
DB相比,在操作語句上更類似關係型資料庫的產品。絕大多數標準的SQL92語句SQLite都能支援。

SQLite的版權允許無任何限制的應用,包括商業性的產品。在參考連結二上提供的SQLite官方主站上可以下載到編譯後的SQLite程式。但推薦應用CVS工具下載最新版本的SQLite原始碼。如果在*nux平臺下,可直接用make編譯。如果在Windows
平臺,常用的有兩種方法,一是應用在Windows平臺下的Linux模擬程式,如MingW或Cygwin提供的make來編譯。二是應用MS
VC平臺編譯。後者設定略有麻煩,但可仿照參考連結五上提供的MS VC6工程檔案的樣例。應用到這個樣例的時候,要注意的是由於SQLite原始碼在不斷更新,如果直接應用樣例所提供的VC6工程檔案編譯會出現一些問題,讀者要根據具體的情況稍微調整一下編譯的設定。

2. 編譯第三方Java介面

SQLite 原始碼是C,而且官方網站上只提供了C和Tcl語言的介面。為了應用Java介面,要採用第三方的介面驅程,可在參考連結三中找到這個Java介面程式。這個介面提供了兩種連線SQLite的方式:一是直接用JNI技術呼叫SQLite的C語言介面,這種方式要求開發人員要對SQLite本身的API也有一定的瞭解。在第二種方式中,介面程式實現了Java標準規範的JDBC介面,這樣開發人員只要對JDBC有了解就可以了。

下面介紹在Windows系統MS VC6環境中編譯SQLite Java介面(同時包括JNI和JDBC兩個介面)的過程。如果你對C語言編譯的設定很熟悉,可以跳這這段介紹。

第一步先把SQLite原始碼編譯成Lib靜態庫檔案。具體的步驟可以直接應用下面參考連結中提供的MS VC6工作區檔案,其中有一個編譯SQLite到靜態庫的設定。編譯成功後得到SQLite.lib檔案。第二步要建立一個新的VC
DLL專案,然後和上面介紹的Berkeley DB在編譯Java本地化介面的設定一樣,在VC的Tools選單Options選項中指定JNI.H等JNI編譯所要的標頭檔案位置。同時還要指定
sqlite.h標頭檔案位置,這個檔案是在生成SQLite靜態庫的時候自動生成的,可以在SQLite.lib檔案所在的工作區目錄下面找到它,例如加入的路徑為C:\sqlite\msvc6。然後在Project選單的setting選項設定Link到SQLite.lib庫檔案,並再次在
Tools選單中Options指定SQLite.lib的查詢路徑。注意有些情況下可能要設定予編譯選項HAVE_SQLITE_COMPILE以便使用SQLite中VM的一些功能。編譯成功後可得到Sqlite_jni.dll檔案。

第三方介面庫中的Java程式碼包含JNI介面和多個版本的JDBC介面程式,可根據你的JRE的版本選擇相應的JDBC程式。編譯這些Java程式碼的過程這裡就不做敘述了。

編譯後的Java類包加上前面得到的Sqlite_jni.dll檔案,組成了SQLite的Java介面庫,在應用Java語言呼叫JDBC或JNI介面時,都是通過應用Java的本地化技術呼叫Sqlite_jni.dll檔案,完成對SQLite資料庫的操作。

3. 應用JNI直接呼叫SQLite功能

下面這段程式碼演示如何應用JNI介面操作SQLite。可以看到Database類的exec()方法是執行SQL語句的關鍵:

 

Database db = new Database();

try {

//開啟資料庫

db.open(“c:\\temp\\mydata.slt”, 0666);

db.interrupt();

db.busy_timeout(1000);

db.busy_handler(null);

db.exec(“create table account (name varchar(10),gale boolean)”

,result);

db.exec(“insert into account values(‘steve’,’m’)”, result);

db.exec(“select * from account”,result);

//關閉資料庫

db.close();

} catch (Exception e) {

e.printStackTrace();

}

4. 應用JDBC連線SQLite

用”SQLite.JDBCDriver”作為JDBC的驅動程式類名。連線JDBC的URL格式為jdbc:sqlite:/path。這裡的path為指定到SQLite資料庫檔案的路徑,例如:

jdbc:sqlite://dirA/dirB/dbfile

jdbc:sqlite://DRIVE:/dirA/dirB/dbfile

jdbc:sqlite://COMPUTERNAME/shareA/dirB/dbfile

 

參考下面的應用JDBC連線SQLite的例程:

 

 

//宣告JDBC驅動程式

Class clz = Class.forName(“SQLite.JDBCDriver”);

//連線資料庫

Connection conn = DriverManager.getConnection(“jdbc:sqlite:/c:/temp/e2.db”);

Statement stmt = conn.createStatement();

//生成person表,包含名子和年齡欄位

stmt.execute(“create table person (name varchar(100),age int)”);

//插入資料

stmt.execute(“insert into person values(‘steve’,25)”);

//用SQL語句讀出資料

result = stmt.executeQuery(“select * from person”);

while(result.next()){

System.out.println(result.getString(1));

System.out.println(result.getInt(2));

}

 

執行程式時要在 Java.exe命令列加入選項java.library.path指定到Sqlite_jni.dll所在的路徑。例如,如果
Sqlite_jni.dll放在c:\sqliteNative
路徑下面,執行類com.e2one.MyClass
的命令列將會是這樣:java -Djava.library.path=c:\sqliteNative com.e2one.MyClass。

 

5. SQLite的特點

SQLite 是無資料型別的資料庫。雖然在生成表結構的時候,要宣告每個域的資料型別,但SQLite並不做任何檢查。開發人員要靠自己的程式控制輸入與讀出資料的型別是正確的。這裡有一個例外,就是當主鍵為整型值時,如果要插入一個非整型值時會產生異常。另外,雖然在插入或讀出資料的時候是不區分型別的,但在比較的時候,不同資料型別是有區別的。比如:

CREATE TABLE MyTable(a INTEGER, b TEXT);

INSERT INTO MyTable VALUES(0,0);

當執行下面的查詢:

SELECT count(*) FROM MyTable WHERE a==’00’;

 

會返回一條記錄,因為欄位a的型別是整型,而數字00與0是相等的。

而執行下面的查詢則不會返回記錄:

SELECT count(*) FROM MyTable WHERE b==’00’;

因為欄位b是字元型別,字元”00″與”0″是不相等的。

SQLite提供了對Transaction的支援。應用Transaction即保證了資料的完整性,也會提高執行速度,因為多條語句一起提交給資料庫的速度會比一條一條的提交方式更快。

對二進位制資料,SQLite不能直接儲存。但可以先將二進位制的資料轉換成ASCII編碼,然後再儲存。Base64編碼機制是最常見的把二進位制資料轉換成ASCII編碼的手段。在SQLite的C語言程式碼encode.c中提供了Base64編碼的功能。對Java而言,在參考連結六中提供的Apache的XML
RPC專案中可以找到一個Base64編碼的例子。

上面介紹了兩個比較常見的嵌入式資料庫,Berkeley DB速度極快,可靠性高,但學習起來有一定難度。SQLite則簡單易用,速度也很快,又可以應用標準的JDBC連線,但它功能卻照Berkeley略有遜色,比如加密功能、二進位制資料的處理等。

 

開源嵌入式資料庫:Berkeley DB和SQLite的比較

摘要深入分析、比較Berkeley DB和sQLite。Berkel ey DB和sQLite是原始碼開放的嵌入式資料庫管理系統,無需安裝,體積小巧,速度又很快;可以很方便地應用在掌上電腦、PDA、車載裝置、行動電話等MySQL、SQL
Server這些大中型資料庫不可實現的嵌入式裝置上。

 

關鍵詞Berkeley DB SOL,ite
嵌入式資料庫

 

1、嵌入式資料庫

通常,我們採用資料庫來實現對資料的儲存、檢索等功能。像MySQL這類基於C/S結構的關係型資料庫系統,雖然代表著目前資料庫應用的主流,卻並不能滿足所有應用場合的需要。很多的應用,僅僅利用到了這些資料庫產品的基本特性而已。有時我們需要的可能只是一個簡單的基於磁碟檔案的資料庫系統,這樣就不必安裝龐大的資料庫伺服器,以簡化資料庫應用程式的設計。在某些特殊應用場合,比如在嵌入式系統中,由於系統的硬體軟體資源都有限,這些資料庫產品就明顯有一些臃腫,甚至是不可實現的。在這些情況下,嵌入式資料庫的優勢就特別明顯了。

嵌入式資料庫通常與作業系統和具體應用整合在一起,無須獨立執行的資料庫引擎,由程式直接呼叫相應的API去實現對資料的存取操作。更直白地講,嵌入式資料庫是一種具備了基本資料庫特性的資料檔案。嵌入式資料庫與其它資料庫產品的區別是,前者是程式驅動式,而後者是引擎響應式。嵌入式資料庫的一個很重要的特點是它們的體積非常小,編譯後的產品也不過幾十KB,在一些移動裝置上極具競爭力。

從目前嵌入式應用的發展趨勢來看,嵌入式資料庫的實現必須充分體現系統的可定製性,即系統選擇的技術路線要面向具體的行業應用,因而研究原始碼開放的嵌入式資料庫具有特殊意義。

 

2、Berkeley DB和SQLite

DBkeley DB是一款健壯的、高速的工業級開放原始碼的嵌入式資料庫管理系統。應用它,程式設計師只需要呼叫一些簡單的API就可以完成對資料的訪問和管理。

Berkeley DB的原始碼有C和Java兩種,函式庫本身只有300KB左右,但卻能夠用來管理多達256TB的資料。Berkeley
DB作為一種嵌入式資料庫系統在許多方面有著獨特的優勢。首先,由於其應用程式和資料庫管理系統執行在相同的程序空間當中,進行資料操作時可以避免繁瑣的程序間通訊,因此耗費在通訊上的開銷自然也就降低到了極低程度。其次,Berkeley DB使用簡單的函式呼叫介面來完成所有的資料庫操作,而不是在資料庫系統中經常用到的SQL語言,避免了對結構化查詢語言進行解析和處理所需的開銷。

SQLite的原始碼是C,其原始碼完全開放。SQLite第一個Alpha版本誕生於2000年5月。今年5月,SQLite又迎來了一個新的里程一SOLite
3。

SQLite有以下特性:支援ACID事務;零配置一無需安裝和管理配置;儲存在單一磁碟檔案中的一個完整的資料庫;資料庫檔案可以在不同位元組順序的機器間自由共享;支援資料庫大小至2TB;足夠小,全部原始碼大致3萬行c程式碼,250KB;比目前流行的大多數資料庫對資料的操作要快;提供了對事務功能和併發處理的支援,應用Transaction既保證了資料的完整性,也會提高執行速度,因為多條語句一起提交給資料庫的速度會比一條一條的提交方式更快;獨立,沒有額外依賴。

目前,對Berkeley DB的研究開發工作主要是美國的sleepycat公司在進行,在國內幾乎沒有關於這方面的研究;而SQLite在國內也是鮮有人問津。

2.1 Berkeley DB和SOLite的資料庫操作

與常用的資料庫管理系統(如MySQL和Oracle等)有所不同,在Berkeley
DB中並沒有資料庫伺服器的概念。應用程式不需要事先同資料庫服務建立起網路連線,而是通過內嵌在程式中的Berkeley DB函式庫來完成對資料的儲存、查詢、修改和刪除等操作。所有與資料庫相關的操作都由函式庫負責統一完成,這樣無論是系統中的多個程序,或者是相同程序中的多個執行緒,都可以在同一時間呼叫訪問資料庫的函式;而底層的資料加鎖、事務日誌和儲存管理等都在Berkeley
DB函式庫中實現。它們對應用程式來講是完全透明的。

Berkeley DB不是關係型的資料庫,不能應用標準的SQL語句對資料庫操作,對它的操作要呼叫專用的API實現。這些API提供了查詢、插入、刪除等功能。比如com.sleepycat.db.Db類代表資料庫物件。Db類的put(
)方法完成的是插入功能;get( )方法完成的是讀出資料的功能;com.sleepycat.db.Dbc是Berkeley DB的遊標類,提供了遍歷資料庫記錄的功能。

使用Berkeley DB提供的函式來進行資料庫的訪問和管理並不複雜。在大多數場合下,只需按照統一的介面標準進行呼叫就可以完成最基本的操作,Berkeley DBEnvironment為一組資料庫同時提供引數設定。更為重要的是,如果要應用更高階的特性,必須要使用Environment功能,比如在要對儲存的資料進行加密儲存、利用其Transaction、資料加密、同步加鎖控制、錯誤日誌等功能的時候。

SQLite的SQL語言很大程度上實現了ANSI SQL92標準,特別是支援檢視、觸發器、事務,支援巢狀SQL。它通過SQL編譯器(SQL
Complier)來實現SQL語言對資料庫進行操作,支援大部分的SQL命令,如attach database、begin
transaction、comment、commit transaction、copy、create index、create
table、create trigger、create view、delete、detach database、drop
index、drop table、drop trigger、drop view、end transaction、explain、expression、insert、On
conflict clause、pragma、replace、rollback transaction、select、update。

當然,也有一部分SQL命令SQLite並不支援。比如:不支援:Exists,雖然支援in(in是Exists的一種情況);不支援多資料庫,如create
table dbl.tablel as select*from db2.table 1;:不支援儲存過程;不支援Alter View/Trigger/Table:不支援Truncate,在SQLite中Delete不帶Where字句時和Truancate的效果是一樣的;不支援Floor和Ceiling函式,還有其它許多的函式;沒有Auto
Increment(自增)欄位,但其實SQLite是支援Auto Increment的,即在將該欄位設定為“INTEGER
PRIMARY KEY”的時候;不支援If Exists等。

 

2.2 Berkeley DB和S0Lite與普通資料庫的差別

Berkeley DB引入了一些新的基本概念,使得資料庫應用程式訪問和管理資料庫變得相對簡單起來。

(1)關鍵字和資料

關鍵字(key)和資料(data)是。Berkeley.DB用來進行資料庫管理的基礎,由這兩者構成的key/data對,組成了資料庫中的一個基本結構單元。整個資料庫實際上就是由許多這樣的結構單元構成的。通過使用這種方式,在通過API函式訪問資料庫時,只需提供關鍵字就能夠訪問到相應的資料。

關鍵字和資料在Berkeley DB中都是用一個名為DBT的簡單結構來表示的。實際上兩者都可以是任意長度的二進位制資料。DBT的作用主要是儲存相應的記憶體地址及其長度,其結構如下所示:

typedef struct {   

void*data;   

u_int32_t size;   

u_int32_t ulen;   

u_int32_f dlen;   

u_int32_f doff;   

u_int32_f flags;   

}DBT;   

在使用Berkeley DB進行資料管理時,預設情況下是一個關鍵字對應於一個資料;但也可以將資料庫配置成一個關鍵字對應於多個資料,而鍵值和資料必須是類com.sleepycat.db.Dbt的物件或其子類的物件。

(2)物件控制代碼

在Berkeley DB函式庫定義的大多數函式都遵循同樣的呼叫原則:首先建立某個結構,然後再呼叫該結構中的某些方法。從程式設計的角度來講,這一點同物件導向的設計原則是非常類似的,即先建立某個物件的一個例項,然後再呼叫該例項的某些方法。正因為如此,.Berkeley DB引入了物件控制代碼的概念來表示例項化後的結構,並且將結構中的成員函式稱為該控制代碼的方法。物件控制代碼的引入使得程式設計師能夠憑藉物件導向的思想,來完成對Berkeley
DB資料庫的訪問和操作。

(3)錯誤處理

對於任何一個函式庫來說,如何對錯誤進行統一的處理都是需要考慮的問題。Berkeley DB提供的所有函式都遵循同樣的錯誤處理原則,即函式成功執行後返回零,否則返回非零值。

對於系統錯誤(如磁碟空間不足),返回的是一個標準的值;而對於非系統錯誤,返回的則是一個特定的錯誤編碼。例如,如果在資料庫中沒有與某個特定關鍵字所對應的資料,那麼在通過該關鍵字檢索資料時就會出現錯誤。此時函式的返回值將是DB—NOTF0uND,表示在資料庫中並沒有所請求的關鍵字。所有標準的e
rrn0值都大於零,而由Berkeley DB定義的特殊錯誤編碼則都小於零。

Berkeley。DB提供了相應的函式來獲得錯誤代號所對應的錯誤描述。一旦有錯誤發生,只需首先呼叫db_strerror( )函式來獲得錯誤描述資訊,然後再呼叫DB一>err()或DB->errx()就可以很輕鬆地輸出格式化後的錯誤資訊。

 

而SQLite最大的特點在於其資料型別為無資料型別(typelessness)。這意味著可以儲存任何型別的資料到所想要儲存的任何表的任何列中,無論這列宣告的資料型別是什麼。雖然在生成表結構的時候,要宣告每個域的資料型別,但sQLite並不做任何檢查。開發人員要靠自己的程式控制輸入與讀出資料的型別。這裡有一個例外,就是當主鍵為整型值時,如果要插入一個非整型值時會產生異常。

誠然,SQLite允許忽略資料型別,但是,仍然建議在Create Table語句中指定資料型別,因為資料型別有利於增強程式的可讀性。SQLite支援常見的資料型別,如VARCHAR、NVARCHAR、TEXT、INTEGER、FLOAT、BOOLEAN、CLOB、BLOB、TIMESTAMP、NUMERIC、VARYING、CHARACTER、NATl0NAI,
VARYINGCHARACTER。

另外,雖然在插入或讀出資料的時候是不區分型別的,但在比較的時候,不同資料型別是有區別的。比如:CREATE TABLE MyTable (a INTEGER,b TEXT);

INSERT INT0 MyTable VALIUES(0,0);

當執行查詢

SELECT count(*)FROM MyTable WHERE a==’00’;時,會返回一條記錄。因為欄位a的型別是整型,而數字00與0是相等的。而執行查詢

SELECT count(*)FROM MyTable WHERE b==‘00’:時,則不會返回記錄。因為欄位b是字元型別,字元“00”與“0”是不相等的。

 

2.3 Betkeley DB和SQLite資料儲存方式比較

Berkeley DB對任何存入的資料都是按原樣直接儲存到資料檔案中去,無論其是二進位制資料還是A S C I I或Unicode等編碼的文字。Berkeley
DB提供了四種儲存資料的模式:Btree、Hash、Queue和Recno。在開啟資料庫的時候,要指定一種儲存模式。比如,上例中open(
)方法中的引數Db.DB_BTREE就是指定以Btree模式開啟資料庫。

SQLite只提供了Btree儲存資料的模式。對二進位制資料,SQLite不能直接儲存,但可以先將二進位制的資料轉換成ASCII編碼,然後再儲存。Base64.編碼機制是最常見的把二進位制資料轉換成ASCII編碼的手段。在SQLite的C語言程式碼encode.c中,提供了Base64編碼的功能。

Btree模式是以排序的二叉樹的方式儲存的,Hash是以線性雜湊表的方式儲存。Queue用邏輯記錄號作為鍵值,以定長的資料為記錄值。Recno方式也以邏輯記錄號作為鍵值,但可以儲存定長或變長的記錄值。這裡提到的邏輯記錄號有兩種,即可變的和固定的。可變邏輯記錄號會根據資料記錄的增加與刪除作相應的變化。Queue模式下,邏輯記錄號只能是固定方式。Recno模式則可通過配置來選擇是採用哪種型別的記錄號作為鍵值。Btree模式也可以通過設定,將可變的邏輯記錄號作為鍵值。

這幾種儲存模式各有優缺點,當鍵值不想用邏輯記錄號時,Btree或Hash是必須的選擇。Btree方式比較適合連續的順序讀取。比如,當鍵值是時間值,如果經常有從某一時間點開始連續讀取後繼的記錄的操作,Btree是一種很好的選擇。對隨機的跳躍式讀取,Hash模式則更為恰當。Queue和Recno都以記錄號為鍵值,但前者適合先進先出的讀取方式。Recno則通常是存取變長文字記錄的理想儲存模式。

 

2.4 Berkeley DB和S0Lite適用的系統

Berkeley DB為許多程式語言提供了實用的API介面,包括C、C 、Java、:Perl、Tcl、Python和PHP等。它適用平臺UNIX/POSIX
systems、win32以及嵌入式作業系統WinCE、VxWorks等。

通過Wrapper,SQLite實現了與其它語言的連線。所謂Wrapper即對SQLite提供的介面進行封裝,使其它語言可以訪問,使用SQLite。SQLite本身提供C和Tcl的介面,世界各地的程式設計師還提供了各種語言的SQLite的介面封裝,如Python、C 、Java、.Net等幾乎所有流行的語言基本都有。sQLite提供一個抽象的作業系統介面層,來保證其在POSIX
與 Win32系統之間的相容性。

 

2.5 其它方面

Berkeley DB沒有資料庫伺服器的概念,使用簡單的函式呼叫介面來完成所有的資料庫操作,不使用SQL語言;介面簡明實用,避免了對結構化查詢語言進行解析和處理所需的開銷,提高了執行速度;速度極快,可靠性高,但學習起來有一定難度。SQLite則簡單易用,速度也很快,但功能卻較Berkeley略有遜色,比如加密功能、二進位制資料的處理等。

Berkeley DB雖然是開源的產品,但對某些條件下的商業性應用,卻不是免費的,而且價格頗為昂貴。這些商業條件包括排除了開源的情況,不發放分佈版本的情況等。SQLite是原始碼完全的開放,可以免費用於任何用途,包括商業目的。

 

3、結語

隨著人們對移動資料處理和管理需求的不斷提高,與各種智慧裝置緊密結合的嵌入式資料庫技術已經得到了學術界、工業界、民用部門等各方面的廣泛重視。嵌入式資料庫將會使得人們希望隨時隨地存取任意思資料資訊的願望成為現實,嵌入式資料庫將無處不在。開源的嵌入式資料庫Berkeley DB和SQLite,核心微小,有能夠充分適應硬體的能力,能很好地適應嵌入式系統的需要。在具體的嵌入式應用中可以根據具體情況選擇應用