使用Spring JDBC初始化数据库时出现SQLiteException

时间:2016-11-01 09:07:40

标签: java sqlite spring-jdbc

我正在尝试使用spring-jdbc创建一个SQLite数据库。我正在使用这种XML配置进行自动初始化:

<jdbc:initialize-database data-source="logDbDataSource" enabled="true">
    <jdbc:script location="classpath:scheme.sql" />
</jdbc:initialize-database>

scheme.sql创建一个用于记录事件的表。我还想使用触发器自动删除旧数据,因此SQL看起来像这样:

CREATE TABLE IF NOT EXISTS events (
    event_id INTEGER PRIMARY KEY AUTOINCREMENT,
    time DATETIME DEFAULT CURRENT_TIMESTAMP,
    value TEXT NOT NULL
);

CREATE TRIGGER IF NOT EXISTS cleanup
AFTER INSERT ON events
BEGIN
    DELETE FROM events WHERE time < datetime('now', '-35 days');
END;

当我使用

手动创建数据库时,这完全正常

sqlite3 eventDb.sqlite < schema.sql

我的问题是,它在启动程序时导致以下异常,由Spring处理:

java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0': Invocation of init method failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 3 of resource class path resource [homectrlLog-schema.sql]: CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at org.atennert.homectrl.Main.main(Main.java:34)
... 6 more
Caused by: org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 3 of resource class path resource [homectrlLog-schema.sql]: CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')
at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:56)
at org.springframework.jdbc.datasource.init.DataSourceInitializer.afterPropertiesSet(DataSourceInitializer.java:84)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
... 18 more
Caused by: org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 3 of resource class path resource [homectrlLog-schema.sql]: CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')
at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.executeSqlScript(ResourceDatabasePopulator.java:202)
at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:135)
at org.springframework.jdbc.datasource.init.CompositeDatabasePopulator.populate(CompositeDatabasePopulator.java:56)
at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:47)
... 21 more
Caused by: org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (near ")": syntax error)
at org.sqlite.core.DB.newSQLException(DB.java:920)
at org.sqlite.core.DB.newSQLException(DB.java:932)
at org.sqlite.core.DB.throwex(DB.java:897)
at org.sqlite.core.NativeDB.prepare(Native Method)
at org.sqlite.core.DB.prepare(DB.java:227)
at org.sqlite.jdbc3.JDBC3Statement.execute(JDBC3Statement.java:60)
at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.executeSqlScript(ResourceDatabasePopulator.java:187)
... 24 more

我最好的猜测是,自动填充和日期时间功能存在一些问题(与日期功能相同)。当我从脚本中删除触发器时,一切正常。

这是SQLite / SQL函数和/或使用Spring JDBC自动初始化的问题吗?我是否必须以不同的方式编写它以使其适用于自动初始化?

1 个答案:

答案 0 :(得分:0)

Failed to execute SQL script statement at line 3 of
resource class path resource [homectrlLog-schema.sql]:
CREATE TRIGGER IF NOT EXISTS cleanup AFTER INSERT ON events ⏎
BEGIN DELETE FROM events WHERE time < datetime('now', '-35 days')

无论您使用什么代码执行脚本,都会在每个分号处拆分SQL。当你有触发器时这是错误的,因为直到最后的END的整个触发器创建必须作为单个语句执行。