Pregunta Spring + SQLite en aplicación de subprocesos múltiples


Estoy desarrollando una aplicación que usa la base de datos SQLite y la primavera. Tengo problemas cuando varios subprocesos intentan modificar la base de datos. Recibo un error:

'El archivo de la base de datos está bloqueado'

Tengo un solo origen de datos configurado:

<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>

y en cada hilo tengo una instancia separada de JdbcDaoSupport que realiza una inserción en la base de datos:

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

La función que realiza la actualización de la base de datos es transaccional (he probado todos los niveles de aislamiento, en cada caso recibo el mismo error).

El mismo código funciona bien cuando se usa otra base de datos (MySql).

¿Cómo puedo resolver esto (sin agregar una sincronización 'manual' en mi código)?


9
2018-02-25 12:33


origen


Respuestas:


No lo he intentado, pero sugiero que, dado que SQLite solo admite una conexión a la vez, debe configurar su fuente de datos para que solo cree una conexión.

Creo que sería algo como lo siguiente ...

<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>

3
2018-03-29 03:16



Solo atrape y vuelva a intentarlo. Este es el comportamiento normal de SQLite.

[edit:] SQLite volverá a intentarlo; este error se produce si los reintentos no funcionan dentro de un período determinado. Puede aumentar el período de varias maneras: http://www.sqlite.org/pragma.html#pragma_busy_timeout  http://www.sqlite.org/c3ref/busy_timeout.html


2
2018-03-30 11:27



Con suerte, tengo la respuesta perfecta para ti, Berkeley DB y el API de SQL. El año pasado Berkeley DB combinó su motor de almacenamiento con la capa SQL de SQLite, proporcionando un producto combinado que ofrece lo mejor de ambos mundos. La ubicuidad y la facilidad de uso de SQLite, con la concurrencia, el rendimiento, la escalabilidad y la fiabilidad de Berkeley DB.

¿Por qué esto resolverá tu problema? Porque Berkeley DB es completamente compatible con SQLite, pero implementa un administrador de bloqueos diferente y más concurrente. Esto significa que en Berkeley DB puede tener múltiples hilos de actualización accediendo a la base de datos al mismo tiempo. Hay un par de libros blancos interesantes sobre el tema, escritos por Mike Owens (el autor de "The Definitive Guide to SQLite"): Evaluación técnica y de rendimiento y Beneficios y diferencias.

Descargo de responsabilidad: soy el gerente de producto de Berkeley DB, así que estoy un poco parcial. Sin embargo, encontrará que las direcciones Berkeley DB SQL API exactamente el problema que plantea: cómo permitir operaciones concurrentes de lectura / escritura en SQLite.


1
2018-02-28 05:52



Con Spring, puede aprovechar el SingleConnectionDataSource. Para mis usos (más de 300 inserciones / segundo), esto funciona bien.

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

1
2017-09-11 20:40