spring + SQLite在多线程应用程序中

时间:2011-02-25 12:33:15

标签: java spring sqlite

我正在开发一个使用SQLite数据库和spring的应用程序。多线程尝试修改数据库时遇到问题 - 我收到错误:

'数据库文件被锁定'

我配置了一个数据源:

<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)"
);

执行数据库更新的函数是事务性的(我已经尝试了所有隔离级别,在每种情况下我都得到相同的错误)。

使用其他数据库(MySql)时,相同的代码工作正常。

如何解决此问题(在我的代码中未添加“手动”同步)?

4 个答案:

答案 0 :(得分: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>

答案 1 :(得分:2)

抓住并重试。这是正常的SQLite行为。

[编辑:] SQLite将重试自己;如果重试在特定时间段内不起作用,则抛出此错误。您可以通过各种方式增加期限:http://www.sqlite.org/pragma.html#pragma_busy_timeout http://www.sqlite.org/c3ref/busy_timeout.html

答案 2 :(得分: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的产品经理,所以我有点偏颇。但是,您会发现Berkeley DB SQL API解决了完全您提出的问题 - 如何在SQLite中允许并发读/写操作。

答案 3 :(得分:1)

使用Spring,您可以利用SingleConnectionDataSource。对于我的用途(300次插入/秒),这很好用。

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