前面有人問到 H2是否支持多進程的方式, 我的回答是可以的,所以心急的小鳥同學馬上就動手了,呵呵,結果自然是失敗。

在h2的文檔里其實明確提到多進程方式應該使用server 的模式來處理,那么我怎么還可以肯定的說h2是可以支持嵌入方式多進程的?

呵呵,其實我在看到文檔里的FileLock的時候提到這個FileLock有幾種模式,其中一種是No,你自己來實現文件保護。 那么也就是說在你熟悉H2的FileLock的協議以后,完全可以搞出不做fileLock的方式,這樣應該就可以支持多進程了同時打開文件。 此種推斷其實yy的成分比較大,因為實現難度頗大,如何做到一個進程支持寫,多個進程支持讀,還是很考一點功夫的。

但是,要支持多進程的讀是非常簡單的, h2以及h2的祖父hsqldb都支持只讀模式,此種模式允許在光盤介質上運行 h2. 所以只要簡單的把數據庫文件的屬性設置為只讀就允許多個進程同時訪問 h2 了。

來段測試代碼

 

public static void main(String[] args) throws IOException, InterruptedException {
  String userId 
= "402880ED166CAED101166CB7032B0004";
  String tt 
= "" + System.currentTimeMillis()/1000;
  
for (int i = 0; i < 100; i++{
     UserInfo user 
= DAOUtil.getUserInfoDAO().selectByPrimaryKey(userId);
     System.out.println(tt 
+ "|" + user.getName());
     Thread.sleep(
2000);
  }

 }


把這段程序同時運行2份, 就可以看到2個進程交替的輸出查詢結果了。

接著繼續琢磨能否做到1個讀寫,多個只讀。
如果直接把FileLock=NO 打開,是否就可以提供多個進程的訪問了? 答案是否, 因為h2采用了類似oracle那樣日志機制,使用日志文件來記錄數據的變化,延遲提交以提高系統性能, 如果能找到方式允許關閉日志文件(從h2提供的參數來看,是有可能做輕微修改實現這個機制的), 就有可能實現一個讀寫,多個只讀了。

至于要做到多個讀寫支持,那么還要解決一個FileLock協議的問題,即如何做到即寫即鎖。這對不能直接操作底層的java可能有太高難度了。
 
至于SQLite的多進程模式是否也是只讀的, 還是更nb的支持每個進程都做讀寫操作,這個我就不知道了。 但是我想后者實現難道實在太大,而且對于桌面應用來說罕有實際意義了,有空我會研究一下。


報著無聊到底的態度跑去sqlite的網站上看了一下, SQLite的多進程模式頗有點意思, 支持進程的同時讀,但是同一時間只支持一個寫, 使用文件系統提供的讀寫鎖來實現。
Multiple processes can be doing a SELECT at the same time. But only one process can be making changes to the database at any moment in time, however.

不過也正如他后面指出的,這種模式效率并不高, 而且在NFS文件系統并不穩定,在WIN XP之前的win32系統更是只能使用模擬方式實現。 我看也是好玩的成分居多。

Under Win95/98/ME which lacks support for reader/writer locks, a probabilistic simulation is used instead. this locking mechanism might not work correctly if the database file is kept on an NFS filesystem

另外產生了一個懷疑, 這種讀寫排隊操作其實是用interface來控制的, 對于都是c/c++或者tcl的進程我可以理解,但是如果是一個java進程和一個c進程的話能有效保證么? 因為java畢竟不是直接操作底層的語言,第三方實現的SQLite的jdbc能提供這種有效鎖么?

SQLite實現這種奇怪模式的原因,是為了保證少量并發操作時的效率,又能保證資源占用的足夠輕量,據說實際應用少并發的情況比較多。 


其實以h2 的高性能和輕量實現,對于桌面應用,這種多進程模式意義已經不大了。h2的server模式和其他輕量數據庫比其實相當靈活,甚至可以在一個進程里關閉另外一個進程的服務,所以這個問題其實也沒多少意義。