2011-02-25 135 views
9

我正在開發一個使用SQLite數據庫和spring的應用程序。我有問題,當多個線程試圖修改數據庫 - 我得到一個錯誤:spring + SQLite在多線程應用程序

「數據庫文件被鎖定」

我配置了一個數據源:

<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" 
     destroy-method="close" lazy-init="true"> 
    <property name="driverClassName" value="org.sqlite.JDBC" /> 
    <property name="url" value="jdbc:sqlite:sample.db" /> 
    <property name="initialSize" value="2" /> 
    <property name="maxActive" value="20" /> 
    <property name="maxIdle" value="5" /> 
    <property name="poolPreparedStatements" value="true" /> 
</bean> 

,並在每個線程我有JdbcDaoSupport的一個單獨的實例執行插入到數據庫:

getJdbcTemplate().update(
    "insert into counts values(15)" 
); 

執行數據庫更新功能是TRANSAC (我嘗試過所有的隔離級別,每種情況下我都會得到相同的錯誤)。

當使用其他數據庫(MySql)時,相同的代碼工作正常。

我該如何解決這個問題(沒有在我的代碼中添加'手動'同步)?

+0

您希望您的應用程序如何併發?回想一下,按照設計,SQLite旨在替代fopen()和-not- for MySQL。如果您需要一個設計用於處理並行數據訪問的2PL或MVCC的RDBMS,那麼您可能希望考慮另一個RDBMS。 MySQL,HSQLDB或Derby都有真正的客戶端 - 服務器支持。 – scottb 2013-08-29 21:09:48

回答

1

希望我有完美的答案 - Berkeley DBSQL API。去年,Berkeley DB將其存儲引擎與SQLite的SQL層結合在一起,提供了一個兩全其美的組合產品。 SQLite的無處不在和易用性,以及Berkeley DB的併發性,性能,可伸縮性和可靠性。

爲什麼這會解決您的問題?因爲Berkeley DB完全兼容SQLite,但是實現了一個不同的,更加併發的鎖管理器。這意味着在Berkeley DB中,可以有多個更新線程同時訪問數據庫。有關該主題的一些有趣的白皮書,由Mike Owens(「SQLite權威指南」的作者)編寫:Technical & Performance EvaluationBenefits and Differences

聲明:我是伯克利數據庫的產品經理,所以我略有偏見。但是,您會發現Berkeley DB SQL API的地址正好是您提到的問題 - 如何允許SQLite中的併發讀取/寫入操作。

+0

Berkley DB的許可證是什麼樣的?我可以免費分發商業應用程序嗎? – 2011-03-29 03:41:24

+0

您可以在這裏找到Berkeley DB許可證:http://bit.ly/g7h1mf。基本上它是一個雙重許可證。開放源代碼項目的開源使用。關閉源應用程序的商業許可或獲得Oracle支持。 – dsegleau 2011-04-05 03:34:18

+0

作爲另一種選擇,HSQLDB(http://www.hsqldb.org)是免費的,可以通過類似GPL的許可證獲得,現在已經在2.3.0版本中,並且已經持續開發超過10年。它具有真正的客戶端 - 服務器(或獨立)支持,成熟的JDBC 4.1驅動程序幾乎完全支持ANSI SQL:2008,並且通過2PL和MVCC模型支持多種訪問。 – scottb 2013-08-29 21:11:58

3

我還沒有嘗試過,但我建議,由於SQLite一次只支持一個連接,所以應該將數據源配置爲只創建一個連接。

我認爲這將是像下面這樣...

<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" lazy-init="true"> 
    <property name="driverClassName" value="org.sqlite.JDBC" /> 
    <property name="url" value="jdbc:sqlite:sample.db" /> < 
    <property name="initialSize" value="1" /> 
    <property name="maxActive" value="1" /> 
    <property name="maxIdle" value="1" /> 
    <property name="poolPreparedStatements" value="true" /> 
</bean> 
0

有了Spring,您可以利用SingleConnectionDataSource。對於我的使用(300+插入/秒),這工作得很好。

@Bean 
public DataSource jdbcDataSource() { 
    SingleConnectionDataSource ds = new SingleConnectionDataSource(); 
    ds.setDriverClassName("org.sqlite.JDBC"); 
    ds.setUrl("jdbc:sqlite:stats.db"); 
    return ds; 
} 
+0

來自SingleConnectionDataSource文檔的引用「顯然,這不支持多線程。」 – PhoneixS 2016-02-04 08:13:34

+0

@PhoneixS實際的查詢不是,不,但是,只要您使用Spring Jdbc類(如JdbcTemplate),Spring就會處理同步。 – wmarbut 2016-02-04 14:55:29