2011-02-25 136 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