spring + SQLite в многопоточном приложении - PullRequest
9 голосов
/ 25 февраля 2011

Я разрабатываю приложение, которое использует базу данных 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 ]

3 голосов
/ 29 марта 2011

Я не пробовал, но я бы посоветовал, учитывая, что 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>
2 голосов
/ 30 марта 2011

Просто поймайте и повторите попытку. Это нормальное поведение SQLite.

[edit:] SQLite повторится сам; эта ошибка выдается, если повторные попытки не работают в течение определенного периода. Вы можете увеличить период различными способами: http://www.sqlite.org/pragma.html#pragma_busy_timeout http://www.sqlite.org/c3ref/busy_timeout.html

1 голос
/ 11 сентября 2015

С помощью Spring вы можете использовать SingleConnectionDataSource. Для моих целей (300+ вставок в секунду) это прекрасно работает.

@Bean
public DataSource jdbcDataSource() {
    SingleConnectionDataSource ds = new SingleConnectionDataSource();
    ds.setDriverClassName("org.sqlite.JDBC");
    ds.setUrl("jdbc:sqlite:stats.db");
    return ds;
}
1 голос
/ 28 февраля 2011

Надеюсь, у меня есть идеальный ответ для вас - Berkeley DB и SQL API . В прошлом году Berkeley DB объединила свой механизм хранения с SQL-уровнем SQLite, создав комбинированный продукт, который предлагает лучшее из обоих миров. Повсеместность и простота использования SQLite, а также параллельность, производительность, масштабируемость и надежность Berkeley DB.

Почему это решит вашу проблему? Потому что Berkeley DB полностью совместим с SQLite, но реализует другой, более параллельный менеджер блокировок. Это означает, что в БД Berkeley вы можете иметь несколько потоков обновлений, обращающихся к базе данных одновременно. Есть несколько интересных статей по этому вопросу, написанных Майком Оуэнсом (автором «Полного руководства по SQLite»): Техническая оценка и оценка производительности и Преимущества и отличия .

Отказ от ответственности: я менеджер по продукту в Berkeley DB, поэтому я немного предвзят. Однако вы обнаружите, что API-интерфейс SQL Berkeley DB решает точно проблему, которую вы затронули - как разрешить одновременные операции чтения / записи в SQLite.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...