2011-02-25 11 views
9

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 - Me aparece un error:spring + SQLite en la aplicación de subprocesos múltiples

'El archivo de base de datos está bloqueado'

que tienen una única fuente de datos configurada:

<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 independiente de la JdbcDaoSupport que realiza una inserción a la base de datos:

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

la función que realiza la actualización de base de datos es Transac tional (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 solucionar esto (sin agregar una sincronización 'manual' en mi código)?

+0

¿Qué tan concurrente espera que sea su aplicación? Recuerde que, por diseño, SQLite está destinado a ser un reemplazo para fopen() y -not- para MySQL. Si necesita un RDBMS que haya sido diseñado para manejar 2PL o MVCC para acceso a datos simultáneos, entonces puede considerar otro RDBMS. MySQL, HSQLDB o Derby tienen soporte real de cliente-servidor. – scottb

Respuesta

1

Afortunadamente, tengo la respuesta perfecta para usted - Berkeley DB y SQL API. 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é resolverá este 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"): Technical & Performance Evaluation y Benefits and Differences.

Descargo de responsabilidad: Soy el Product Manager de Berkeley DB, así que estoy un poco parcial. Sin embargo, encontrará que la API Berkeley DB SQL atiende exactamente el problema que usted plantea: cómo permitir operaciones concurrentes de lectura/escritura en SQLite.

+0

¿Cómo es la licencia de Berkley DB? ¿Puedo distribuirlo con una aplicación comercial sin costo? –

+0

Puede encontrar la licencia de Berkeley DB aquí: http://bit.ly/g7h1mf. Básicamente es una licencia dual. Uso de código abierto para proyectos de código abierto. Licencia comercial para aplicaciones de código cerrado u obtener soporte de Oracle. – dsegleau

+0

Como otra alternativa, HSQLDB (http://www.hsqldb.org) es gratuito, está disponible bajo una licencia GPL, ahora se encuentra en la versión 2.3.0 y se ha desarrollado continuamente durante más de 10 años. Tiene soporte real de cliente-servidor (o independiente), un controlador maduro JDBC 4.1, tiene soporte casi completo para ANSI SQL: 2008 y admite acceso múltiple a través de modelos 2PL y MVCC. – scottb

3

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

creo que sería algo parecido a 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> 
0

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; 
} 
+0

Cita de la documentación de SingleConnectionDataSource "Obviamente, esto no es capaz de multi-threading". – PhoneixS

+0

@PhoneixS Las consultas reales no son, no, pero Spring maneja la sincronización siempre que use clases jdbc de primavera como JdbcTemplate. – wmarbut

Cuestiones relacionadas