I want to get serial numbers with the help of database.
Here is what I want:
1.read the entity from database and lock it
2.increase the serial number and upadte the entity.
I am asuming the first thread can lock the record and the other thread won't work until the first thread commits its transaction, however, I got the opposite of what I want.
below is my code:
Repository:
public interface ActivityNoGeneratorRepository extends BaseRepository<ActivityNoGenerator, Long> {
#Lock(LockModeType.PESSIMISTIC_WRITE)
#Query(value = "select generator from ActivityNoGenerator generator where id=:id")
ActivityNoGenerator getGeneratorByIdForUpdate(#Param("id") Long id);
}
Service:
#Service
public class ActivityNoGeneratorServiceImpl implements IActivityNoGeneratorService {
#Autowired
private ActivityNoGeneratorRepository activityNoGeneratorRepository;
#Override
#Transactional
public String getActivityNo() {
ActivityNoGenerator activityNoGenerator = activityNoGeneratorRepository.getGeneratorByIdForUpdate(1L);
System.out.println(1);
Integer currentValue = activityNoGenerator.getCurrentValue() + 1;
if (!StringUtils.equals(DateFormatUtils.format(new Date(), "yyyyMM"), DateFormatUtils.format(activityNoGenerator.getLastAccessTime(), "yyyyMM"))) {
currentValue = 1;
}
String serialNum = String.format("%0" + activityNoGenerator.getWidth() + "d", currentValue);
String activityNo = activityNoGenerator.getPrefix() + activityNoGenerator.getPlatformCode() + DateFormatUtils.format(new Date(), "yyyyMM") + serialNum;
activityNoGenerator.setCurrentValue(currentValue);
activityNoGenerator.setLastAccessTime(new Date());
activityNoGeneratorRepository.save(activityNoGenerator);
return activityNo;
}
}
Test:
public class IActivityNoGeneratorServiceTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:spring/applicationContext.xml");
final IActivityNoGeneratorService activityNoGeneratorService = applicationContext.getBean(IActivityNoGeneratorService.class);
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
#Override
public void run() {
System.out.println(activityNoGeneratorService.getActivityNo());
}
}).start();
}
}
}
Result:
Hibernate:
select
activityno0_.id as id1_3_,
activityno0_.current_value as current_2_3_,
activityno0_.last_access_time as last_acc3_3_,
activityno0_.platform_code as platform4_3_,
activityno0_.platform_name as platform5_3_,
activityno0_.prefix as prefix6_3_,
activityno0_.step as step7_3_,
activityno0_.width as width8_3_
from
activity_no_generator activityno0_
where
activityno0_.id=? for update
Hibernate:
select
activityno0_.id as id1_3_,
activityno0_.current_value as current_2_3_,
activityno0_.last_access_time as last_acc3_3_,
activityno0_.platform_code as platform4_3_,
activityno0_.platform_name as platform5_3_,
activityno0_.prefix as prefix6_3_,
activityno0_.step as step7_3_,
activityno0_.width as width8_3_
from
activity_no_generator activityno0_
where
activityno0_.id=? for update
1
1
Hibernate:
update
activity_no_generator
set
current_value=?,
last_access_time=?,
platform_code=?,
platform_name=?,
prefix=?,
step=?,
width=?
where
id=?
Hibernate:
update
activity_no_generator
set
current_value=?,
last_access_time=?,
platform_code=?,
platform_name=?,
prefix=?,
step=?,
width=?
where
id=?
Exception in thread "Thread-6" org.springframework.orm.jpa.JpaSystemException: commit failed; nested exception is org.hibernate.TransactionException: commit failed
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
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:483)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:290)
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.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy44.getActivityNo(Unknown Source)
at com.lemall.srd.pop.activity.oa.service.IActivityNoGeneratorServiceTest$1.run(IActivityNoGeneratorServiceTest.java:18)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.TransactionException: commit failed
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:187)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
... 10 more
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)
... 12 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.Util.getInstance(Util.java:387)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:950)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3966)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3902)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2526)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2673)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2545)
at com.mysql.jdbc.ConnectionImpl.commit(ConnectionImpl.java:1614)
at com.zaxxer.hikari.pool.ProxyConnection.commit(ProxyConnection.java:355)
at com.zaxxer.hikari.pool.HikariProxyConnection.commit(HikariProxyConnection.java)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:112)
... 13 more
HD1020012017050631
Process finished with exit code 0
I debug my code and find the second thread executed without waiting the first thread commit.
Any clue what mistake I make? Thanks very much!
What I see is that you are missing the #Transactional annotation in your repository method which might be the reason that your service method and repo method are running in two different transactions. Also use the Propagation.Required option in your transactional annotation.
Related
We have multi-schema DB, and each schema contains algorithm_execution table First I get the schema-list, and then prepare the update query for one-by-one in loop for each schema-name and run EntityManager.executeUpdate() which is failing with below error. Not sure what is the root cause as table exists in schema and I am able to run same update query on table using pgsql client.
Edit:
Tried to query/update the entity using spring data repository as well but that also fails. Can't we query a table on each schema one-by-one in for loop, before running the query we are specifying the schema in the context.
The method that is failing -
Code:
private void updateJobStatus(EntityManager entityManager, String schemaName, AlgorithmExecution execution) throws Exception{
try {
private static final String UPDATE_JOB_STATUS_QUERY =
String updateQuery = "UPDATE "+schemaName+".algorithm_execution SET job_status = :job_status, modification_time = :modification_time, error_message = :error_message, job_logs = :job_logs WHERE id = :id";
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.createNativeQuery(updateQuery)
.setParameter("job_status", execution.getJobStatus())
.setParameter("modification_time", execution.getModifiedTime())
.setParameter("error_message", execution.getErrorMessage())
.setParameter("job_logs", execution.getJobLogs())
.setParameter("id", execution.getId())
.executeUpdate();
transaction.commit();
} catch ( Exception ex) {
LOGGER.warn("An exception occured during updateJobStatus, error {}", ex.getMessage());
LOGGER.debug("An exception occured during updateJobStatus",ex);
throw new Exception("An exception occured during updateJobStatus", ex);
}
}
Hibernate internal logs below update query in the logs:
2020-12-15 12:11:28.159 +0000 [main] [DEBUG] - org.hibernate.SQL [org.hibernate.engine.jdbc.spi.SqlStatementLogger:logStatement:128] - update algorithm_execution set algorithm_checksum=?, algorithm_id=?, create_time=?, error_message=?, job_logs=?, job_name=?, job_status=?, job_summary=?, job_type=?, modification_time=?, next_execution=?, owner=?, previous_execution=?, start_time=?, tenant_id=? where id=?
Below is the exception stack trace -
Exception:
ava.lang.Exception: An exception occured during updateJobStatus
at com.bmc.aif.jobmanager.jobmanagement.AIFJobManagementTask.updateJobStatus(AIFJobManagementTask.java:144)
at com.bmc.aif.jobmanager.jobmanagement.AIFJobManagementTask.jobStatusFailedOrUnknown(AIFJobManagementTask.java:118)
at com.bmc.aif.jobmanager.jobmanagement.AIFJobManagementTask.executeTasks(AIFJobManagementTask.java:79)
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.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:895)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at com.bmc.aif.jobmanager.jobmanagement.AIFJobManagementTask.main(AIFJobManagementTask.java:149)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1356)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1339)
at org.hibernate.query.internal.NativeQueryImpl.beforeQuery(NativeQueryImpl.java:264)
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1610)
at com.bmc.aif.jobmanager.jobmanagement.AIFJobManagementTask.updateJobStatus(AIFJobManagementTask.java:139)
... 25 common frames omitted
Caused by: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:103)
at 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.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3430)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3292)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3704)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:201)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1352)
... 29 common frames omitted
Caused by: org.postgresql.util.PSQLException: ERROR: relation "algorithm_execution" does not exist
Position: 8
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2532)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2267)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:312)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:448)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:369)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:153)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:119)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 41 common frames omitted
Hi,
I am able to fix above issue using CrudRepository like -
#Repository
public interface AlgorithmExecutionRepository extends CrudRepository<AlgorithmExecution, UUID>
#Autowired
AlgorithmExecutionRepository executionRepository;
private void updateJobStatus(AlgorithmExecution execution)
throws Exception {
try {
LOGGER.info("Set the RequestContext, the current tenant is {}", RequestContext.getCurrentTenant());
LOGGER.info("updating the execution {} for jobId {} for status {} of tenant {}",
execution.getId(),execution.getAlgorithmId(), execution.getJobStatus(), execution.getTenantId());
executionRepository.save(execution);
LOGGER.info("Syccessfully updated the execution {} for jobId {} for status {} of tenant {}",
execution.getId(),execution.getAlgorithmId(), execution.getJobStatus(), execution.getTenantId());
} catch (Exception ex) {
LOGGER.warn("An exception occured during updateJobStatus, error {}", ex.getMessage());
LOGGER.debug("An exception occured during updateJobStatus", ex);
throw new Exception("An exception occured during updateJobStatus", ex);
}finally {
RequestContext.clear();
LOGGER.info("Cleared the RequestContext, the current tenant is {}", RequestContext.getCurrentTenant());
}
}
Also, extended MultiTenantConnectionProvider to override the hibernate connection method. Need to set the schema and get the connection to that schema and then update the table.
#Component
public class TenantConnectionProvider implements MultiTenantConnectionProvider {
#Override
public void releaseAnyConnection(Connection connection) throws SQLException {
connection.close();
}
#Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
logger.info("Get connection for tenant {}", tenantIdentifier);
final Connection connection = getAnyConnection();
connection.setSchema(Constants.SCHEMA_PREFIX + "_" +tenantIdentifier.toUpperCase().trim());
return connection;
}
#Override
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
logger.info("Release connection for tenant {}", tenantIdentifier);
releaseAnyConnection(connection);
}
}
I have created a function which is trying to save something in DB where version is enabled hence it can give optimistic lock exception. I catch the exception and try it again after fetching from DB. I am also using #transactional annotation to start a new transaction everytime. But I get org.springframework.orm.ObjectOptimisticLockingFailureException even before my save function is called.
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void handleExecution(#NonNull final Execution execution, final Map<String, Object> data, final String pattern) {
log.info("Processing notification pattern {} with data {} for execution {}",pattern,data,execution);
if (ExecutionStatus.PROCESSING.equals(execution.getStatus()) || ExecutionStatus.WAITING.equals(execution.getStatus())) {
//Put the received notification in the execution queue
List<Map<String, Object>> notificationQueue = execution.getNotificationQueue();
Map<String,Object> notificationMap = new HashMap<>();
notificationMap.put(pattern, data);
notificationQueue.add(notificationMap);
execution.setNotificationQueue(notificationQueue);
try
{
executionBuilder.save(execution);
}
catch(OptimisticLockingFailureException e)
{
log.error("Save of execution {} failed due to optimistic locking, retrying",execution);
//Fetch the object again and call again
Optional<Execution> savedExecution = executionBuilder.findOne(execution.getId());
if(savedExecution.isPresent())
{
handleExecution(savedExecution.get(),data, pattern);
}
}
}
}
The detailed exception which I get is:
2018-07-11 08:09:39.408 INFO 8251 --- [thread_pool_executor-45]
o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of
batch it still contained JDBC statements
2018-07-11 08:09:39.408 ERROR 8251 --- [thread_pool_executor-45] reactor.bus.EventBus : Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:320) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at com.gor.platform.process.support.service.builder.ExecutionBuilderImpl$$EnhancerBySpringCGLIB$$a036b2e6.patch(<generated>) ~[process-service-2.0-SNAPSHOT.jar:2.0-SNAPSHOT]
at com.gor.platform.process.support.service.event.receiver.ProcessEventReceiver.accept(ProcessEventReceiver.java:58) ~[process-service-2.0-SNAPSHOT.jar:2.0-SNAPSHOT]
at com.gor.platform.process.support.service.event.receiver.ProcessEventReceiver.accept(ProcessEventReceiver.java:23) ~[process-service-2.0-SNAPSHOT.jar:2.0-SNAPSHOT]
at reactor.bus.EventBus$3.accept(EventBus.java:317) ~[reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.EventBus$3.accept(EventBus.java:310) ~[reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.routing.ConsumerFilteringRouter.route(ConsumerFilteringRouter.java:72) ~[reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.EventBus.accept(EventBus.java:591) [reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.bus.EventBus.accept(EventBus.java:63) [reactor-bus-2.0.8.RELEASE.jar:na]
at reactor.core.dispatch.AbstractLifecycleDispatcher.route(AbstractLifecycleDispatcher.java:160) [reactor-core-2.0.8.RELEASE.jar:na]
at reactor.core.dispatch.MultiThreadDispatcher$MultiThreadTask.run(MultiThreadDispatcher.java:74) [reactor-core-2.0.8.RELEASE.jar:na]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3082) ~[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]
The executionBuilder.save internally calls dao.save which is not seen in the stack trace. Why is this exception getting thrown even before the save is called. When save is called then the exception is caught and things work fine. But occasionally this exception is thrown without the save and hence doesn't get caught.
My gut feeling says it has something to do with #Transactional.
For the information my application is multithreaded and many thread might modify the same data at the same time.
Any help would be appreciated.
you can handle optimistic lock using spring retry option inside the controller.
Download for this class
import org.springframework.retry.annotation.Retryable;
For Example
#RequestMapping(value = CommonConstants.DETAILS_ADD_OR_UPDATE, method = RequestMethod.POST)
#Retryable(value = { StaleObjectStateException.class,
HibernateOptimisticLockingFailureException.class }, maxAttempts = 1, backoff = #Backoff(delay = 5000))
public ResponseJson addOrUpdate(#RequestBody User user, HttpServletRequest request) {
try{
responseJson.setResponse(adminService.update(userId, user));
}
catch (DataIntegrityViolationException | ConstraintViolationException e) {
ErrorInfo errorInfo = errorCodeHelper.getErrorInfo(CommonConstants.E1071_ERROR_CODE,
CommonConstants.E1071_ERROR_DESCRIPTION);
throw new ServiceException(errorInfo);
}
return responseJson;
}
This is the important one add on the top of the method
#Retryable(value = { StaleObjectStateException.class,
HibernateOptimisticLockingFailureException.class }, maxAttempts = 1, backoff = #Backoff(delay = 5000))
ObjectOptimisticLockingFailureException occurs after transaction is completed.
If you are looking for 1 or 2 retries:
In controller you can handle else you have follow what faizakram has given:
try {
service.method_name(requestObj);
} catch (ObjectOptimisticLockingFailureException e) {
try {
service.method_name(requestObj);
} catch (ObjectOptimisticLockingFailureException oex) {
//throw error here
}
}
In service:
method_name() throws ObjectOptimisticLockingFailureException{
//business loginc
}
I use Play Framework 2.3.4, Java8, Ebean.
Ebean transaction code is not working.
Please your help.
Java Code
Ebean.execute(new TxRunnable() {
public void run() {
User user = new User();
user.id = 1;
user.save();
}
});
server error log is
play.api.Application$$anon$1: Execution exception[[IllegalStateException: Transaction is Inactive]]
at play.api.Application$class.handleError(Application.scala:296) ~[com.typesafe.play.play_2.11-2.3.4.jar:2.3.4]
at play.api.DefaultApplication.handleError(Application.scala:402) [com.typesafe.play.play_2.11-2.3.4.jar:2.3.4]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [com.typesafe.play.play_2.11-2.3.4.jar:2.3.4]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$3$$anonfun$applyOrElse$4.apply(PlayDefaultUpstreamHandler.scala:320) [com.typesafe.play.play_2.11-2.3.4.jar:2.3.4]
at scala.Option.map(Option.scala:145) [org.scala-lang.scala-library-2.11.1.jar:na]
Caused by: java.lang.IllegalStateException: Transaction is Inactive
at com.avaje.ebeaninternal.server.transaction.JdbcTransaction.commit(JdbcTransaction.java:583) ~[org.avaje.ebeanorm.avaje-ebeanorm-3.3.4.jar:na]
at com.avaje.ebeaninternal.api.ScopeTrans.onFinally(ScopeTrans.java:101) ~[org.avaje.ebeanorm.avaje-ebeanorm-3.3.4.jar:na]
at com.avaje.ebeaninternal.server.core.DefaultServer.execute(DefaultServer.java:724) ~[org.avaje.ebeanorm.avaje-ebeanorm-3.3.4.jar:na]
at com.avaje.ebeaninternal.server.core.DefaultServer.execute(DefaultServer.java:709) ~[org.avaje.ebeanorm.avaje-ebeanorm-3.3.4.jar:na]
at com.avaje.ebean.Ebean.execute(Ebean.java:1264) ~[org.avaje.ebeanorm.avaje-ebeanorm-3.3.4.jar:na]
Thanks.
provide transaction scope
TxScope txScope = TxScope.requiresNew();
Ebean.execute(txScope, new TxRunnable() {
public void run() {
User user = new User();
user.id = 1;
user.save();
}
});
I am using spring with hibernate and when I am trying to insert a data which already exists, it throws DataIntegrityViolationException.
So to handle this exception I have placed a try/catch block in my save method in DAO layer, but it's not getting caught.
After that I placed a try/catch block in save method of service layer also but there also its not getting caught.
I have a testMain method in my service layer and when I am handling there its getting caught there.
Please help how to handle this in my DAO layer
public class TestMain {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext applicationContext = SpringUtil
.getApplicationContextInstance();
UserDaoService userDaoService = applicationContext.getBean("userDaoService",
UserDaoService.class);
UserDaoImpl userDao = applicationContext.getBean("userDaoImpl",
UserDaoImpl.class);
User user = new User();
user.setActive(true);
user.setEmail("shariquealam01#gmail.com");
user.setFirstName("Md");
user.setMiddleName("Sharique");
user.setLastName("Alam");
user.setId(1);
user.setPassword("123");
user.setUserName("shariquealam01");
userDaoService.saveUser(user);
}
}
#Service
public class UserDaoService {
#Autowired
public UserDao userDao;
#Transactional
public void saveUser(User user){
System.out.println("User Saving");
/*user.setActive(true);
user.setEmail("shariquealam06#gmail.com");
user.setFirstName("Md");
user.setMiddleName("Sharique");
user.setLastName("Alam");
user.setId(6);
user.setPassword("123");
user.setUserName("shariquealam06");*/
userDao.saveUser(user) ;
/*try{
System.out.println("Inside Service Try");
userDao.saveUser(user);
} catch (Exception e){
System.out.println("Exception Occured "+e);
}*/
// deleteUser(3);
}
}
#Repository
public class UserDaoImpl implements UserDao {
#Autowired
private SessionFactory sessionFactory;
public Role getRole(int id){
Session session = getSessionFactory().getCurrentSession();
Role role = (Role) session.get(Role.class, id);
return role;
}
#Override
public void saveUser(User user) {
// Session session = getSessionFactory().getCurrentSession();
/*role.setRoleId(102);
role.setRoleName("User");*/
// role.getUsers().add(user);
/*session.save(user);*/
//logger.info( "Executing Query to ADD User"); //Since this query is important for the state of application, have info logging
Role role = getRole(102);
user.getRoles().add(role);
Session session = sessionFactory.getCurrentSession();
session.save( user );
//userId = user.getId();
//logger.info( "User ADDED to DB with userId as {}", user.getId() );
//session.save(role);
}
}
Exception in thread "main" org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:163)
at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:730)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:592)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:515)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
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:653)
at com.sharique.service.UserDaoService$$EnhancerBySpringCGLIB$$956522ab.saveUser(<generated>)
at com.sharique.main.TestMain.main(TestMain.java:40)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:129)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:211)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:62)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3124)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3581)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:351)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)
... 9 more
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Violation of PRIMARY KEY constraint 'PK__USER_DET__F3BEEBFF77DFC722'. Cannot insert duplicate key in object 'dbo.USER_DETAILS'.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1515)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:404)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:350)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:5696)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1715)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:180)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:155)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:314)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:98)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:98)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
... 22 more
The exception, as the stack trace should show, doesn't happen when you call persist() or save(). It happens when flush() is called, i.e. when the SQL insert statements are actually executed. And flush() is called automatically just before the transaction commits.
You could call flush() explicitely and catch the exception, but that would be useless, because Hibernate exceptions are irrecoverable. They leave the session in an unusable state. The only safe thing to do when facing such an exception is to rolback the transaction and close the session.
So do the right thing: use autogenerated primary keys and/or check that the data doesn't exist, using a query, before trying to insert it.
I just add a new column on an entity and a strange thing is happening.
The entity was previously:
int publishedDayNb;
public int getPublishedDayNb() {
return publishedDayNb;
}
public void setPublishedDayNb(int publishedDayNb) {
this.publishedDayNb = publishedDayNb;
}
And the entity is now:
int publishedDayNb;
int publishedDayNbSinceLastPublication;
public int getPublishedDayNb() {
return publishedDayNb;
}
public void setPublishedDayNb(int publishedDayNb) {
this.publishedDayNb = publishedDayNb;
}
#Column(name="published_days_since_last_pub")
public int getPublishedDayNbSinceLastPublication() {
return publishedDayNbSinceLastPublication;
}
public void setPublishedDayNbSinceLastPublication(int publishedDayNbSinceLastPublication) {
this.publishedDayNbSinceLastPublication = publishedDayNbSinceLastPublication;
}
As you can see i've just added a column.
The sql script to do that in database was:
alter table mytable add published_days_since_last_pub number(10,0);
update mytable set published_days_since_last_pub=0;
alter table mytable modify published_days_since_last_pub number(10,0) not null;
I'm doing a java batch processing, reading a file, inserting new entity entries, and updating existing ones.
It works fine in local and in dev server, but in validation server, i've got this error during a new entity processing (insert)
BATCH 03/05/2011 06:41:11 WARN
[JDBCExceptionReporter.java:77] - SQL
Error: 1400, SQLState: 23000 BATCH
03/05/2011 06:41:11 ERROR
[JDBCExceptionReporter.java:78] -
ORA-01400: cannot insert NULL into
("mydb"."mytable"."PUBLISHED_DAYS_SINCE_LAST_PUB")
BATCH 03/05/2011 06:41:11 ERROR
[AbstractFlushingEventListener.java:301]
- Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException:
could not insert:
[com.xxx.myentity]
at
org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at
org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2262)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2655)
at
org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:60)
at
org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at
org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at
org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
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:1001)
at
org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:339)
at
org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at
org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:655)
at
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:732)
at
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
at
com.xxx.eplatform.websites.webstore.batch.processor.DistrinetDataProcessor$$EnhancerByCGLIB$$42d43018.processDistrinetLine() at
com.xxx.eplatform.websites.webstore.batch.services.impl.WebstoreImporterServiceImpl.importDistrinetFile(WebstoreImporterServiceImpl.java:71)
at
com.xxx.eplatform.websites.webstore.batch.WebstoreImportBatch.execute(WebstoreImportBatch.java:142)
at
com.xxx.eplatform.websites.webstore.batch.WebstoreImportBatch.main(WebstoreImportBatch.java:104)
Caused by: java.sql.SQLException:
ORA-01400: cannot insert NULL into
("mydb"."mytable"."PUBLISHED_DAYS_SINCE_LAST_PUB")
at
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
at
oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:745)
at
oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:216)
at
oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:966)
at
oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1170)
at
oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3339)
at
oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3423)
at
org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2242)
... 21 more
I don't understand what is wrong since the primitive type i added to the entity is always initialized at 0 so it shouldn't be null.
I've also looked my entity class with javap and it seems it's the right version of the entity: my new attribute is there.
Anyone? Thanks
Just Change int to Integer and see if it help