【发布时间】:2017-05-04 16:17:11
【问题描述】:
我正在开发一个使用 ucanaccess 3.0.7 连接到 Microsoft Access 2010 数据库的 Spring Boot 应用程序。我从数据库读取没有问题,但我看到这个“无效的事务状态:只读 SQL 事务”错误在尝试保存到数据库时偶尔会弹出。
我可以通过在关闭 .accdb 文件的情况下导航到我的网页来重现此错误;然后当我尝试保存到数据库时,我会收到错误消息。如果我打开 .accdb 文件并尝试再次保存,它将起作用。
接下来,如果我在打开 .accdb 文件的情况下重新加载网页并尝试保存到数据库;我将再次收到只读错误。如果我关闭 .accdb 文件并尝试再次保存,它将起作用。
不知道这可能是什么问题,希望有人可以帮助我。
错误:
WARN 8360 --- [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: -3706, SQLState: 25006
ERROR 8360 --- [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper : UCAExc:::3.0.7 invalid transaction state: read-only SQL-transaction
ERROR 8360 --- [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: could not prepare statement; nested exception is org.hibernate.exception.GenericJDBCException: could not prepare statement] with root cause
org.hsqldb.HsqlException: invalid transaction state: read-only SQL-transaction
at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.Session.checkReadWrite(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.StatementDMQL.checkAccessRights(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.StatementDML.<init>(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.ParserDML.compileUpdateStatement(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.ParserCommand.compilePart(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.ParserCommand.compileStatement(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.Session.compileStatement(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.StatementManager.compile(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.Session.execute(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.jdbc.JDBCPreparedStatement.<init>(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at org.hsqldb.jdbc.JDBCConnection.prepareStatement(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
at net.ucanaccess.jdbc.UcanaccessConnection.prepareStatement(UcanaccessConnection.java:524) ~[ucanaccess-3.0.7.jar:3.0.7]
at sun.reflect.GeneratedMethodAccessor73.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101]
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126) ~[tomcat-jdbc-8.5.6.jar:na]
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.5.6.jar:na]
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:81) ~[tomcat-jdbc-8.5.6.jar:na]
at com.sun.proxy.$Proxy84.prepareStatement(Unknown Source) ~[na:na]
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:87) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareStatement(StatementPreparerImpl.java:78) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.buildBatchStatement(AbstractBatchImpl.java:136) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.getBatchStatement(AbstractBatchImpl.java:125) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3025) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2961) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3341) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:145) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1282) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:465) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2963) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2339) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ~[spring-orm-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) ~[spring-data-jpa-1.10.5.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at com.sun.proxy.$Proxy112.save(Unknown Source) ~[na:na]
编辑
经过进一步测试,Hibernate 似乎在第一次读取事务完成后锁定了我的数据库。
我的控制器
@RequestMapping("/")
public String index(Model model) {
List<SystemLuEntity> systems = systemLuRepository.findAll();
List<ControlLuEntity> entities = controlLuRepository.findAll();
model.addAttribute("items", entities);
model.addAttribute("systems", systems);
return "index";
}
修改控制器以测试保存到数据库(收到只读错误)
findAll() 后保存实体
@RequestMapping("/")
public String index(Model model) {
List<SystemLuEntity> systems = systemLuRepository.findAll();
List<ControlLuEntity> entities = controlLuRepository.findAll();
model.addAttribute("items", entities);
model.addAttribute("systems", systems);
ControlStatusEntity entity = new ControlStatusEntity();
Random random = new Random();
entity.setId(25);
entity.setComment(String.valueOf(random.nextInt()));
controlStatusRepository.save(entity);
return "index";
}
修改控制器以测试保存到数据库(第一次保存成功,之后失败)
在 findAll() 之前保存实体
@RequestMapping("/")
public String index(Model model) {
ControlStatusEntity entity = new ControlStatusEntity();
Random random = new Random();
entity.setId(25);
entity.setComment(String.valueOf(random.nextInt()));
controlStatusRepository.save(entity);
List<SystemLuEntity> systems = systemLuRepository.findAll();
List<ControlLuEntity> entities = controlLuRepository.findAll();
model.addAttribute("items", entities);
model.addAttribute("systems", systems);
return "index";
}
修改控制器以测试保存到数据库(每次都成功保存)
只是保存;不调用 findAll()
@RequestMapping("/")
public String index(Model model) {
ControlStatusEntity entity = new ControlStatusEntity();
Random random = new Random();
entity.setId(25);
entity.setComment(String.valueOf(random.nextInt()));
controlStatusRepository.save(entity);
return "index";
}
【问题讨论】:
-
看起来 Hibernate 正在创建一个 HSQLDB 事务,该事务由于某种原因被强制为只读模式,并且欺骗 .accdb 导致 UCanAccess 重新构建后备数据库,因此终止了交易。也许在尝试将更新应用到数据库之前,尝试明确要求 Hibernate 立即提交。
-
感谢您的评论,戈德。我会试试这个,让你知道会发生什么。
-
@GordThompson 我在我的问题中添加了一些额外的发现。
-
听起来默认事务隔离对您的应用程序来说可能过于严格。答案here 提到了一个可以设置为控制 Hibernate 使用的默认事务隔离的属性。也许尝试设置
<property name="hibernate.connection.isolation">1</property>(未提交阅读)看看是否有帮助。 -
你做了所有的努力,所以继续发布答案,我会投赞成票。
标签: ms-access spring-boot hsqldb ucanaccess