Hibernate session not synchronize when deadlock detected - java

I have following scenario to save my object
// Started transaction
User objUser = getUser("123");// get user from DB
objUser.set(...)
.
.
UserAddress objUserAddress = objUser.getUserAddress();
objUserAddress.set(..);
.
.
hibernateSession.flush(); //#Line 1
hibernateSession.saveOrUpdate(objUserAddress); //#Line 2
hibernateSession.flush(); //#Line 3
hibernateSession.saveOrUpdate(objUser); //#Line 4
// Commit transaction
Here is hibernate mapping between User and Address class
<class name="com.service.core.bo.impl.User" table="USERS">
.
.
<many-to-one name="userAddress" class="com.service.core.bo.impl.UserAddress"
column="ADDRESS_ID" not-null="false" unique="true" cascade="save-update"
lazy="false" />
.
.
</class>
At some time I received deadlock on #Line 1. here is exception stack.
[2017-12-12 11:15:02.131 GMT] WARN [] [] [] [] [] [] [] [] [] http-bio-8280-exec-14 org.hibernate.util.JDBCExceptionReporter - SQL Error: 60, SQLState: 61000
[2017-12-12 11:15:02.131 GMT] ERROR [] [] [] [] [] [] [] [] [] http-bio-8280-exec-14 org.hibernate.util.JDBCExceptionReporter - ORA-00060: deadlock detected while waiting for resource
[2017-12-12 11:15:02.131 GMT] ERROR [] [] [] [] [] [] [] [] [] http-bio-8280-exec-14 org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.LockAcquisitionException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:87)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at sun.reflect.GeneratedMethodAccessor706.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
.
.
Caused by: java.sql.BatchUpdateException: ORA-00060: deadlock detected while waiting for resource
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:12296)
at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:246)
at sun.reflect.GeneratedMethodAccessor553.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at oracle.ucp.jdbc.proxy.StatementProxyFactory.invoke(StatementProxyFactory.java:353)
at oracle.ucp.jdbc.proxy.PreparedStatementProxyFactory.invoke(PreparedStatementProxyFactory.java:178)
at com.sun.proxy.$Proxy66.executeBatch(Unknown Source)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 71 more
Problem is, this error is not consistent. This may occur once or multiple times in a day and other day, nothing.
Not sure why flush() causing Could not synchronize database state with session and ORA-00060: deadlock detected while waiting for resource. I found some links like Could not synchronize database state with session for session state but my actual cause is deadlock as per above exception.

Could not synchronize database state with session is an generic hibernate error that can have multiple root causes.
The error that you should focus on is:
ORA-00060: deadlock detected while waiting for resource
This is Oracle specific and it happens when updates to the same data (row in the database) is happening from more then one connection. Whenever Oracle (and just about any database, in fact) it updates a row, it locks it for the duration of the update. If another update is attempted on the same line while it is locked, then this error happens.
Here is the official error explanation from Oracle:
ORA-00060: deadlock detected while waiting for resource
Cause: Transactions deadlocked one another while waiting for resources.
Action: Look at the trace file to see the transactions and resources involved. Retry if necessary.
One way to address this problem is to use versioning:
https://www.intertech.com/Blog/versioning-optimistic-locking-in-hibernate/
This adds a version column to the table, which is automatically incremented when the row is updated. Before the update the version is checked and if it is higher then the one expected, the updated is not even updated and a specific error is thrown, which you can handle. Usually handling involves reloading the info from the database for that entity, reset its values to what you want and then save.

Related

SQL Warning with Spring boot and Sybase

I am getting a lot of SQL Warning in the logs with the spring boot and sybase.
o.h.engine.jdbc.spi.SqlExceptionHelper : [] SQL Warning Code: 0, SQLState: 010SK
o.h.engine.jdbc.spi.SqlExceptionHelper : [] 010SK: Database cannot set connection option SET_READONLY_TRUE.
o.h.engine.jdbc.spi.SqlExceptionHelper : [] 010SK: Database cannot set connection option SET_READONLY_FALSE.
Could anyone explain the reason behind this?
Solution 1:
java.sql.Connection has a setReadOnly(boolean) method that is meant to notify the database of the type of result set being requested in order to perform any optimizations. However Sybase ASE doesn't require any optimizations, therefore setReadOnly() produces a SQLWarning.
In order to suppress the message you'll need to update the spt_mda table in the MASTER database.
update spt_mda set querytype = 4, set query = '0'
where mdinfo = 'SET_READONLY_FALSE'
and
update spt_mda set querytype = 4, set query = '0'
where mdinfo = 'SET_READONLY_TRUE'
These two entries (they are the only ones) are set to a querytype of 3 by default, which means "not supported", which explains the SQLWarning.
Changing them to a 4 (meaning boolean values) with a query type of "0" basically causes the JDBC Driver to return false without the warning..
Solution 2:
You might turn off/on on logging for specific part of hibernate logging modules, these are different configurations:
# Hibernate logging
# Log everything (a lot of information, but very useful for troubleshooting)
log4j.logger.org.hibernate=FATAL
# Log all SQL DML statements as they are executed
log4j.logger.org.hibernate.SQL=INHERITED
# Log all JDBC parameters
log4j.logger.org.hibernate.type=INHERITED
# Log all SQL DDL statements as they are executed
log4j.logger.org.hibernate.tool.hbm2ddl=INHERITED
# Log the state of all entities (max 20 entities) associated with the session at flush time
log4j.logger.org.hibernate.pretty=INHERITED
# Log all second-level cache activity
log4j.logger.org.hibernate.cache=INHERITED
# Log all OSCache activity - used by Hibernate
log4j.logger.com.opensymphony.oscache=INHERITED
# Log transaction related activity
log4j.logger.org.hibernate.transaction=INHERITED
# Log all JDBC resource acquisition
log4j.logger.org.hibernate.jdbc=INHERITED
# Log all JAAS authorization requests
log4j.logger.org.hibernate.secure=INHERITED
Possible values:
OFF
FATAL
ERROR
WARN
INFO
DEBUG
TRACE
ALL

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.

H2: JdbcSQLException: This CLOB or BLOB reference timed out

Upon using h2 in java (calling getBytes function) I'm getting the following error. Google didn't get me anywhere. I wonder if anyone has clues what's going on.
Caused by: org.h2.jdbc.JdbcSQLException: This CLOB or BLOB reference timed out: "533668/-3" [90039-190]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.store.LobStorageMap.getInputStream(LobStorageMap.java:287)
at org.h2.value.ValueLobDb.getInputStream(ValueLobDb.java:384)
at org.h2.value.ValueLobDb.getBytesNoCopy(ValueLobDb.java:318)
at org.h2.value.ValueLobDb.getBytes(ValueLobDb.java:304)
at org.h2.jdbc.JdbcResultSet.getBytes(JdbcResultSet.java:1059)
at edu.illinois.cs.cogcomp.srl.caches.SentenceDBHandler$1.next(SentenceDBHandler.java:214)
This error message can occur if you have a long running transaction for instance. You can increase the timeout by setting the LOB_TIMEOUT property on the database connection.
Database setting LOB_TIMEOUT (default: 300000, which means 5 minutes).
The number of milliseconds a temporary LOB reference is kept until it times out. After the timeout, the LOB is no longer accessible using this reference.
https://www.h2database.com/javadoc/org/h2/engine/DbSettings.html#LOB_TIMEOUT

Commit failed while step execution data was already updated

I am getting Commit failed while step execution data was already updated error when spring batch try to commit the records. Any help would be greatly appreciated.
I am using HIbernate JPA .
It is working for lesser number of records. Throwing error when the record count is high.
Stack Trace:
2016-01-20 08:49:45 INFO TaskletStep:359 - Commit failed while step execution data was already updated. Reverting to old version.
2016-01-20 08:49:45 ERROR TaskletStep:370 - Rolling back with transaction in unknown state
2016-01-20 08:49:45 ERROR AbstractStep:225 - Encountered an error executing step uploadFiles in job fileUploadJob
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:524)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
I had same error "Commit failed while step execution data was already updated. Reverting to old version" and I solved it by using " #Transactional(propagation = Propagation.REQUIRES_NEW)" annotation above the method where the records were committed.

JPA Deadlock when delete from a table in several parallel threads

I have several Threads, with different Transactions and EntityManagers, that must refresh events of an object. To refresh these events, first I delete the old ones to after persist the new. With one thread it works good, but with several it occurs dead lock when deleting the event.
All Threads are deleting different objects, and sometimes, in different tables. So why this competition for resources occurring? I'm using the primary key to JPA block the right object. I looked if there is other code that are also using the resource, but I didn't found it. Is JPA locking the whole table instead of the row?
Exception in thread "Thread-4" javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-00060: deadlock detected while waiting for resource
Error Code: 60
Call: DELETE FROM event WHERE ((id = ?) AND (version = ?))
bind => [426687, 1]
Query: DeleteObjectQuery(Event[id=426687,tipo=BDE,status=1,data=java.util.GregorianCalendar[time=1431489600000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTim
Here is the OOracle Trace File.
*** 2015-07-05 15:21:02.351
DEADLOCK DETECTED ( ORA-00060 )
[Transaction Deadlock]
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TM-00007874-00000000 44 29 SX 51 185 SX SSX
TX-00020021-00000a5f 51 185 X 44 29 X
session 29: DID 0001-002C-0000000D session 185: DID 0001-0033-00000004
session 185: DID 0001-0033-00000004 session 29: DID 0001-002C-0000000D
Rows waited on:
Session 29: obj - rowid = 00007874 - AAAHh0AABAAAO2fAAX
(dictionary objn - 30836, file - 1, block - 60831, slot - 23)
Session 185: no row
----- Information for the OTHER waiting sessions -----
Session 185:
sid: 185 ser: 3883 audsid: 422763 user: 55/LUPAZUL_DEV
flags: (0x41) USR/- flags_idl: (0x1) BSY/-/-/-/-/-
flags2: (0x40009) -/-
pid: 51 O/S info: user: oracle, term: UNKNOWN, ospid: 9977
image: oracle#sydney-oracle11gexpress
client details:
O/S info: user: Pickler, term: unknown, ospid: 1234
machine: MacBook program: JDBC Thin Client
application name: JDBC Thin Client, hash value=2546894660
current SQL:
DELETE FROM correios_event WHERE ((id = :1 ) AND (version = :2 ))
----- End of information for the OTHER waiting sessions -----
Information for THIS session:
----- Current SQL Statement for this session (sql_id=fcrp8hfyatd79) -----
DELETE FROM correios_destiny WHERE ((id = :1 ) AND (version = :2 ))
I solved the bug.
I had two JPA entities with bidirectional #OneToOne relationship. When I called the EntityManager.remove() I was not passing the owner of the relationship. This made Oracle throw DeadLockException.
This way EclipseLink created two statements on the same entity to delete.
It seems a bug to me, JPA implementation should handle this.

Categories

Resources