How does em.flush causes LockAcquisitionException? - java

I'm refactoring a code from a project and during my lunch I started looking at some error logs from the application running the old code. It's somehow related to the EntityManager#flush method (this project is using Hibernate as the persistence framework).
There's a process that select some X rows (up to 10) from a process and lock them by using for update -- #Lock(LockModeType.PESSIMISTIC_WRITE). This is within a transaction boundary and it uses Spring Data JPA Repositories and Spring Transaction Management (#Transactional).
I saw the following code (just a representation, since the actual code is huge):
#Transactional
public void method() {
// uses #Lock(LockModeType.PESSIMISTIC_WRITE)
List<Foo> entities = fooRepository.selectForUpdate();
// iterates all entities, do some work and update them
for (Foo foo: entities) {
foo.setX(321);
}
// save the list of entities
fooRepository.saveAll(foo);
// flush() is causing LockAcquisitionException
fooRepository.flush();
}
By looking at the logs, the line fooRepository.flush() is causing a LockAcquisitionException. This is really strange to me and I've never saw this before. If the rows were already selected successfully, how do this exception occurs while flushing?
Funny enough, this only happens during high throughputs periods of the day.
A snippet from the StackTrace:
org.springframework.dao.CannotAcquireLockException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.LockAcquisitionException: could not execute statement
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:287)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy150.flush(Unknown Source)
at xxx.xxx.xxx.xxx.MyClass.method(MyClass.java:764)
....
As per the last line of this snippet, you see that the error occurs on line 764, which is exactly where the flush happens.
Why is this happening?

Without the full stack trace and logs it is impossible to help you. The exception usually indicates a deadlock or lock timeout, so maybe you are flushing something that isn't locked yet. When flushing, MySQL tries to lock the rows in some order and if some other TX acquires locks in a different order, you see a deadlock like this.

Related

hibernate running error, restart normally

The program runs for a period of time and always reports an error, restarting and returning to normal, the error is as follows:
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not prepare statementat org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1626)at org.hibernate.query.Query.getResultList(Query.java:165)at net.skycloud.platform.user.repository.KeycloakGroupDao.findAll(KeycloakGroupDao.java:111)at net.skycloud.platform.user.service.UserGroupService.getAllUserGroups(UserGroupService.java:247)at net.skycloud.platform.user.api.rest.UserController.searchUserAndGroup(UserController.java:362)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.base/java.lang.reflect.Method.invoke(Method.java:566)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)at javax.servlet.http.HttpServlet.service(HttpServlet.java:645)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:769)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.base/java.lang.Thread.run(Thread.java:829)Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statementat org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:186)at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:151)at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:2122)at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2059)at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2037)at org.hibernate.loader.Loader.doQuery(Loader.java:956)at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:357)at org.hibernate.loader.Loader.doList(Loader.java:2868)at org.hibernate.loader.Loader.doList(Loader.java:2850)at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2682)at org.hibernate.loader.Loader.list(Loader.java:2677)at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338)at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2181)at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1204)at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:177)at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1617)... 52 common frames omittedCaused by: java.sql.SQLException: Connection is closedat com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection$0(ProxyConnection.java:515)at com.sun.proxy.$Proxy156.prepareStatement(Unknown Source)at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:337)at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java)at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:149)at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:176)... 67 common frames omitted
I hope to fix this bug
Its a database operations level exception using EntityManager or any other session manager (which is not your case) as exception suggest, how ever it can have many reasons such database has closed the connection or network terminated the connection socket, and to solve it you can configure to keep the connection alive but remember you can not hold the hibernate session alive for long time by default .
Also you may have look on OSIV anti pattern.

How do deal with h2 databases inability to deal with interrupts

How do deal with h2 database inability to deal with interrupts, I was occasionally seeing that my embedded h2 database appeared to get corrupted, in particular I had amended an ExecutorService so that if a task took too long it would cancel the task. The task would be cancelled okay but then subsequent database access failed with exceptions such as
23/07/2019 14.23.31:BST:DeleteDuplicatesController:start:SEVERE: commit failed
org.hibernate.TransactionException: commit failed
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:187)
at com.jthink.songkong.db.ReportCache.save(ReportCache.java:46)
at com.jthink.songkong.reports.AbstractReport.setReportDatabaseObject(AbstractReport.java:365)
at com.jthink.songkong.reports.DeleteDuplicatesReport.setReportDatabaseObject(DeleteDuplicatesReport.java:333)
at com.jthink.songkong.reports.DeleteDuplicatesReport.closeReport(DeleteDuplicatesReport.java:377)
at com.jthink.songkong.analyse.toplevelanalyzer.DeleteDuplicatesController.deleteAnyDups(DeleteDuplicatesController.java:606)
at com.jthink.songkong.analyse.toplevelanalyzer.DeleteDuplicatesController.start(DeleteDuplicatesController.java:665)
at com.jthink.songkong.ui.swingworker.DeleteDuplicates.doInBackground(DeleteDuplicates.java:43)
at com.jthink.songkong.ui.swingworker.DeleteDuplicates.doInBackground(DeleteDuplicates.java:20)
at javax.swing.SwingWorker$1.call(SwingWorker.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javax.swing.SwingWorker.run(SwingWorker.java:334)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.TransactionException: unable to commit against JDBC connection
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:116)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:180)
... 14 more
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "java.lang.IllegalStateException: Reading from nio:C:/Users/Paul/AppData/Roaming/SongKong/Database/Database.mv.db failed; file length -1 read length 4096 at 1541494 [1.4.199/1]"; SQL statement:
COMMIT [50000-199]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:502)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:427)
at org.h2.message.DbException.get(DbException.java:194)
at org.h2.message.DbException.convert(DbException.java:347)
at org.h2.command.Command.executeUpdate(Command.java:280)
at org.h2.jdbc.JdbcConnection.commit(JdbcConnection.java:542)
at com.mchange.v2.c3p0.impl.NewProxyConnection.commit(NewProxyConnection.java:1284)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:112)
... 15 more
Caused by: java.lang.IllegalStateException: Reading from nio:C:/Users/Paul/AppData/Roaming/SongKong/Database/Database.mv.db failed; file length -1 read length 4096 at 1541494 [1.4.199/1]
at org.h2.mvstore.DataUtils.newIllegalStateException(DataUtils.java:883)
at org.h2.mvstore.DataUtils.readFully(DataUtils.java:420)
at org.h2.mvstore.FileStore.readFully(FileStore.java:98)
at org.h2.mvstore.MVStore.readBufferForPage(MVStore.java:1048)
at org.h2.mvstore.MVStore.readPage(MVStore.java:2186)
at org.h2.mvstore.MVMap.readPage(MVMap.java:554)
at org.h2.mvstore.Page$NonLeaf.getChildPage(Page.java:1086)
at org.h2.mvstore.Page.get(Page.java:221)
at org.h2.mvstore.MVMap.get(MVMap.java:402)
at org.h2.mvstore.MVMap.get(MVMap.java:389)
at org.h2.mvstore.MVStore.getMapName(MVStore.java:2737)
at org.h2.mvstore.MVStore.renameMap(MVStore.java:2650)
at org.h2.mvstore.tx.TransactionStore.commit(TransactionStore.java:453)
at org.h2.mvstore.tx.Transaction.commit(Transaction.java:389)
at org.h2.engine.Session.commit(Session.java:691)
at org.h2.command.dml.TransactionCommand.update(TransactionCommand.java:46)
at org.h2.command.CommandContainer.update(CommandContainer.java:133)
at org.h2.command.Command.executeUpdate(Command.java:267)
... 18 more
Caused by: java.nio.channels.ClosedChannelException
at sun.nio.ch.FileChannelImpl.ensureOpen(FileChannelImpl.java:110)
at sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:721)
at org.h2.store.fs.FileNio.read(FilePathNio.java:74)
at org.h2.mvstore.DataUtils.readFully(DataUtils.java:406)
... 34 more
23/07/2019 14.23.31:BST:Errors:addError:SEVERE: Adding Error:commit failed
I have since found this issue
Basically if using H2 in embedded mode, and it receives an interrupt then all subsequent access fails until the thread pool is close and reopened. In the example I give of a process having to be cancelled because it appears to be stuck there is no solution except for interrupting
I also have another case whereby usually the controller thread that doesn't directly do a database work itself so I was struggling to see why when an interrupt occurred why this would cause database errors since this is handled by controller thread. I have now worked out the issue is that Im using an ExecutorService with a fixed size BlockingQueue (so that we dont have a big queue build up in memory), but if the queue gets full then new task is actually executed by the controller thread (because of CallerRunsPolicy), so the controller thread can be making calls to database after all.
Im using H2 with hibernate and in both cases calling the following immediately after the interrupt
HibernateUtil.closeFactory();
seems to solve the issue, however I guess this means that any other threads with hibernate sessions will be broken, but at least newly opened sessins will be okay. So im not particularly happy with this workaround, any other ideas ?
Using H2 as a server is not a solution since the whole point of H2 was an embedded db self contained within application.
Although not properly documented using the async protocol allows a connection to be interrupted without breaking all other connections.

No vote issue due to add same value multiple time in ehcache in spring boot

My issue is I am handle ehcache by my self not using hibernate.
eg. Whenever I required any Object First I get from cache if not found then get from db and put into cache.so, next time It is available in cache.
issue : when two thread try to get that object at that time first of all both have not found object in cache. first both get from db and then both try to put object in cache.At that time second thread gave error of No vote.
can you please suggest any best way to manage ehcache manually. If you not getting my question feel free to contact.
Error
org.springframework.transaction.UnexpectedRollbackException: JTA
transaction unexpectedly rolled back (maybe due to a timeout); nested
exception is javax.transaction.RollbackException: Prepare: NO vote
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1026)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
This exception means that when a transaction is requested to commit but has already been rolled back due to a timeout.You can increase the transaction timeout to resolve this.

ORMLite exception : java.sql.SQLException: ResultSet already requested

In one of our Java app we have a SQLite DB and multiple threads read and write to the same DB (different tables). These multiple threads however use the same database connection object (ORMLite's DaoManager.createDao()).
We are getting this SQLException (Resultset already requested) randomly whenever some insert/update statement is executing. Below is the stack trace of one such instance.
java.sql.SQLException: Unable to run insert stmt on object ABCD-164: INSERT INTO `pos_order` (`bill_number` ,`order_status` ,`order_type` ,`payment_mode` ,`reference_bill_number` ,`table_selected` ,`sub_total` ,`discountable_sub_total` ,`total` ,`total_discount` ,`discount_type` ,`discount_value` ,`total_tax` ,`service_charge` ,`service_tax` ,`vat` ,`delivery_charge` ,`packaging_charge` ,`amount_paid` ,`waiter` ,`delivery_boy` ,`order_source` ,`delivery_source` ,`card_type` ,`card_name` ,`client_creation_time` ,`client_updation_time` ,`order_comment` ,`customer_feedback` ,`is_deleted` ,`payment_status` ,`pos_outlet_id` ,`is_sync` ,`delivery_status` ,`shipment_id` ,`response_code` ,`delivery_time` ,`custom_packaging_charge_enable` ,`custom_delivery_charge_enable` ,`receipt_printed` ,`total_person` ,`order_origin` ,`json` ,`oo_system_id` ,`pre_order` ,`pre_order_time` ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
at com.j256.ormlite.misc.SqlExceptionUtil.create(SqlExceptionUtil.java:22)
at com.j256.ormlite.stmt.mapped.MappedCreate.insert(MappedCreate.java:135)
at com.j256.ormlite.stmt.StatementExecutor.create(StatementExecutor.java:450)
at com.j256.ormlite.dao.BaseDaoImpl.create(BaseDaoImpl.java:310)
at com.j256.ormlite.dao.BaseDaoImpl.createOrUpdate(BaseDaoImpl.java:336)
at com.limetray.pos.dbmanagers.implementations.PosOrderDaoImpl.insert(PosOrderDaoImpl.java:50)
at com.limetray.pos.controllers.BillingSectionController.lambda$10(BillingSectionController.java:808)
at com.limetray.pos.utilities.SingleTaskExecutor$1.call(SingleTaskExecutor.java:37)
at javafx.concurrent.Task$TaskCallable.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: ResultSet already requested
at org.sqlite.jdbc3.JDBC3Statement.getResultSet(JDBC3Statement.java:136)
at org.sqlite.jdbc3.JDBC3PreparedStatement.executeQuery(JDBC3PreparedStatement.java:69)
at org.sqlite.jdbc3.JDBC3DatabaseMetaData.getGeneratedKeys(JDBC3DatabaseMetaData.java:1796)
at org.sqlite.jdbc3.JDBC3Statement.getGeneratedKeys(JDBC3Statement.java:346)
at com.j256.ormlite.jdbc.JdbcDatabaseConnection.insert(JdbcDatabaseConnection.java:173)
at com.j256.ormlite.stmt.mapped.MappedCreate.insert(MappedCreate.java:91)
... 13 more
Any help would be much appreciated. Thanks.
In one of our Java app we have a SQLite DB and multiple threads read and write to the same DB (different tables).
With the SQLite database, you can only have one connection to it at a time. The database has internal locking that ensures that no two threads are using the same connection at the same time but that doesn't stop the DAOs from allowing multiple threads to cause problems like you are having.
Caused by: java.sql.SQLException: ResultSet already requested
In your case, because multiple threads are using the same connection, this exception is getting thrown when one thread asks for results on a connection that has already been asked my another thread. Their queries are improperly being interleaved.
It's important to realize that this has nothing to do with the underlying database. Sqlite has its own locking that blocks concurrent access by multiple threads. But in this case, we are having problems with multiple threads using the same connection.
Right now ORMLite does not have a ConnectionSource that provides a synchronized single connection to the underlying database so you will have to do your own external locking. You could extend the JdbcSingleConnectionSource class and use a ReentrantLock to enforce the controls. Maybe something like:
public class LockedJdbcSingleConnectionSource extends JdbcSingleConnectionSource {
private final ReentrantLock lock = new ReentrantLock();
// called from JdbcSingleConnectionSource.getReadOnlyConnection() ...
public DatabaseConnection getReadWriteConnection() {
lock.lock();
return super.getReadWriteConnection();
}
public void releaseConnection(DatabaseConnection connection) {
super.releaseConnection(connection);
lock.unlock();
}
}

Is Hibernate using pessimistic or optimistic locking?

All my classes have an
#Version
annotation, so I assumed they were using optimistic locking.
But I the following exception in my logs that seem to indicate Im using pessimistic locking. So which is it ? (I want to use optimistic locking)
update Song set acoustidFingerprint=?, acoustidId=?, album=?, albumArtist=?, albumArtistSort=?, albumSort=?, amazonId=?, arranger=?, artist=?, artistSort=?, artists=?, barcode=?, bpm=?, catalogNo=?, comment=?, composer=?, composerSort=?, conductor=?, country=?, custom1=?, custom2=?, custom3=?, custom4=?, custom5=?, discNo=?, discSubtitle=?, discTotal=?, djmixer=?, duration=?, encoder=?, engineer=?, fbpm=?, filename=?, genre=?, grouping=?, isCompilation=?, isrc=?, keyOfSong=?, language=?, lastModified=?, lyricist=?, lyrics=?, media=?, mixer=?, mood=?, musicbrainzArtistId=?, musicbrainzDiscId=?, musicbrainzOriginalReleaseId=?, musicbrainzRecordingId=?, musicbrainzReleaseArtistId=?, musicbrainzReleaseCountry=?, musicbrainzReleaseGroupId=?, musicbrainzReleaseId=?, musicbrainzReleaseStatus=?, musicbrainzReleaseType=?, musicbrainzWorkId=?, musicipId=?, occasion=?, originalAlbum=?, originalArtist=?, originalLyricist=?, originalYear=?, producer=?, quality=?, rating=?, recordLabel=?, releaseYear=?, remixer=?, script=?, subtitle=?, tags=?, tempo=?, title=?, titleSort=?, track=?, trackTotal=?, urlDiscogsArtistSite=?, urlDiscogsReleaseSite=?, urlLyricsSite=?, urlOfficialArtistSite=?, urlOfficialReleaseSite=?, urlWikipediaArtistSite=?, urlWikipediaReleaseSite=?, version=? where recNo=? and version=? [50200-172]
**org.hibernate.PessimisticLockException: Timeout trying to lock table ; SQL statement:**
update Song set acoustidFingerprint=?, acoustidId=?, album=?, albumArtist=?, albumArtistSort=?, albumSort=?, amazonId=?, arranger=?, artist=?, artistSort=?, artists=?, barcode=?, bpm=?, catalogNo=?, comment=?, composer=?, composerSort=?, conductor=?, country=?, custom1=?, custom2=?, custom3=?, custom4=?, custom5=?, discNo=?, discSubtitle=?, discTotal=?, djmixer=?, duration=?, encoder=?, engineer=?, fbpm=?, filename=?, genre=?, grouping=?, isCompilation=?, isrc=?, keyOfSong=?, language=?, lastModified=?, lyricist=?, lyrics=?, media=?, mixer=?, mood=?, musicbrainzArtistId=?, musicbrainzDiscId=?, musicbrainzOriginalReleaseId=?, musicbrainzRecordingId=?, musicbrainzReleaseArtistId=?, musicbrainzReleaseCountry=?, musicbrainzReleaseGroupId=?, musicbrainzReleaseId=?, musicbrainzReleaseStatus=?, musicbrainzReleaseType=?, musicbrainzWorkId=?, musicipId=?, occasion=?, originalAlbum=?, originalArtist=?, originalLyricist=?, originalYear=?, producer=?, quality=?, rating=?, recordLabel=?, releaseYear=?, remixer=?, script=?, subtitle=?, tags=?, tempo=?, title=?, titleSort=?, track=?, trackTotal=?, urlDiscogsArtistSite=?, urlDiscogsReleaseSite=?, urlLyricsSite=?, urlOfficialArtistSite=?, urlOfficialReleaseSite=?, urlWikipediaArtistSite=?, urlWikipediaReleaseSite=?, version=? where recNo=? and version=? [50200-172]
at org.hibernate.dialect.H2Dialect$2.convert(H2Dialect.java:317)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at com.sun.proxy.$Proxy22.executeUpdate(Unknown Source)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3123)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3021)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3350)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:140)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:276)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:62)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1182)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1611)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:374)
at com.jthink.songkong.db.SongCache.loadSongsFromDatabase(SongCache.java:58)
at com.jthink.songkong.analyse.analyser.SongGroup.getSongs(SongGroup.java:48)
at com.jthink.songkong.analyse.analyser.MergeMusicBrainzMatches.matchToMissingTracks(MergeMusicBrainzMatches.java:318)
at com.jthink.songkong.analyse.analyser.MergeMusicBrainzMatches.call(MergeMusicBrainzMatches.java:105)
at com.jthink.songkong.analyse.analyser.MergeMusicBrainzMatches.call(MergeMusicBrainzMatches.java:40)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.h2.jdbc.JdbcSQLException: Timeout trying to lock table ; SQL statement:
update Song set acoustidFingerprint=?, acoustidId=?, album=?, albumArtist=?, albumArtistSort=?, albumSort=?, amazonId=?, arranger=?, artist=?, artistSort=?, artists=?, barcode=?, bpm=?, catalogNo=?, comment=?, composer=?, composerSort=?, conductor=?, country=?, custom1=?, custom2=?, custom3=?, custom4=?, custom5=?, discNo=?, discSubtitle=?, discTotal=?, djmixer=?, duration=?, encoder=?, engineer=?, fbpm=?, filename=?, genre=?, grouping=?, isCompilation=?, isrc=?, keyOfSong=?, language=?, lastModified=?, lyricist=?, lyrics=?, media=?, mixer=?, mood=?, musicbrainzArtistId=?, musicbrainzDiscId=?, musicbrainzOriginalReleaseId=?, musicbrainzRecordingId=?, musicbrainzReleaseArtistId=?, musicbrainzReleaseCountry=?, musicbrainzReleaseGroupId=?, musicbrainzReleaseId=?, musicbrainzReleaseStatus=?, musicbrainzReleaseType=?, musicbrainzWorkId=?, musicipId=?, occasion=?, originalAlbum=?, originalArtist=?, originalLyricist=?, originalYear=?, producer=?, quality=?, rating=?, recordLabel=?, releaseYear=?, remixer=?, script=?, subtitle=?, tags=?, tempo=?, title=?, titleSort=?, track=?, trackTotal=?, urlDiscogsArtistSite=?, urlDiscogsReleaseSite=?, urlLyricsSite=?, urlOfficialArtistSite=?, urlOfficialReleaseSite=?, urlWikipediaArtistSite=?, urlWikipediaReleaseSite=?, version=? where recNo=? and version=? [50200-172]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:158)
at org.h2.command.Command.filterConcurrentUpdate(Command.java:281)
at org.h2.command.Command.executeUpdate(Command.java:237)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:154)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:140)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at sun.reflect.GeneratedMethodAccessor55.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
... 24 more
This exception is due to Lock TimeOut.
Caused by: org.h2.jdbc.JdbcSQLException: Timeout trying to lock table ;
Check a solution here
Also hibernate provides mechanisms for implementing both types of locking in your applications.
Your locking strategy can be either optimistic or pessimistic.
Optimistic
Optimistic locking assumes that multiple transactions can complete without affecting each other, and that therefore transactions can proceed without locking the data resources that they affect. Before committing, each transaction verifies that no other transaction has modified its data. If the check reveals conflicting modifications, the committing transaction rolls back[1].
Pessimistic
Pessimistic locking assumes that concurrent transactions will conflict with each other, and requires resources to be locked after they are read and only unlocked after the application has finished using the data.
Details can be found here
You are using optimistic locking, as your UPDATE statement already indicates:
where recNo=? and version=?
The presence of the version column is what optimistic locking is all about.
You were misled by the PessimisticLockException which might be caused by an explicit or an implicit row-level lock.
It is most likely, that you will use a different database for Testing, than you do in LIVE environment.
H2 can produce errors, which might not appear on LIVE Database like Oracle, MySQL a.s.o.. Means even your code is correct, but the H2 can possibly be messing around.
The MVCC=true works perfectly.
At the same time you should ensure that you have full integration tests on LIVE like systems for your use case in order to verify the LIVE Database behaviour.

Categories

Resources