Je reçois cette exception avec le niveau d'isolement SERIALIZED sur JobRepository dans Spring Batch:
org.springframework.dao.CannotSerializeTransactionException: PreparedStatementCallback; SQL [INSERT into DATAFEED_APP.BATCH_JOB_INSTANCE(JOB_INSTANCE_ID, JOB_NAME, JOB_KEY, VERSION) values (?, ?, ?, ?)]; ORA-08177: can't serialize access for this transaction
; L'exception imbriquée est Java.sql.SQLException: ORA-08177: impossible de sérialiser l'accès pour cette transaction
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.Java:269)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.Java:72)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.Java:603)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.Java:812)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.Java:868)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.Java:872)
at org.springframework.batch.core.repository.dao.JdbcJobInstanceDao.createJobInstance(JdbcJobInstanceDao.Java:105)
at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.Java:135)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:39)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:25)
at Java.lang.reflect.Method.invoke(Method.Java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:172)
at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.Java:172)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:204)
at $Proxy27.createJobExecution(Unknown Source)
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.Java:124)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:39)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:25)
at Java.lang.reflect.Method.invoke(Method.Java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:150)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.Java:117)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:204)
at $Proxy61.run(Unknown Source)
lors de l'exécution d'un seul travail, rien d'autre en parallèle. Lorsque je modifie le niveau d'isolement pour JobRepository en ISOLATION_READ_COMMITTED, l'exception a disparu.
Quelle est la raison de cette exception?
Le niveau d'isolation par défaut pour cette méthode est SERIALIZABLE, qui est assez agressif: READ_COMMITTED fonctionnerait aussi bien; READ_UNCOMMITTED serait acceptable si deux processus ne risquent pas de entrer en collision de cette façon. Cependant, puisque l'appel à la méthode create * est assez court, il est peu probable que SERIALIZED pose problème, tant que la plate-forme de base de données le supporte}.
J'ai eu le même problème, et l'isolation au niveau de jobRepository est la clé, voici un exemple de code qui fonctionne pour moi:
<batch:job-repository id="jobRepository"
data-source="dataSource" transaction-manager="transactionManager"
isolation-level-for-create="READ_COMMITTED" table-prefix="SB_" />
Lorsque vous utilisez des transactions sérialisées, vous devez augmenter le paramètre initrans sur la table conformément au Oracle Docs . Pour traiter les transactions sérialisées, il faut être 3 ou plus.
alter table BATCH_.... INITRANS 3
Nous avons essayé de faire passer INI_TRANS à 100 et nous rencontrions toujours des problèmes
J'ai trouvé cet article qui suggère d'ajouter ROWDEPENDENCIES à la création de tables.
http://www.devx.com/dbzone/Article/41591?pf=true
Pour moi avec INI_TRANS et maintenant ROWDEPENDENCIES, les exceptions pour Serialized ont disparu.
Mise à jour: s'avère ne pas être une solution parfaite. Nous avons eu un événement de cette exception SERIALIZED qui s'est passé pendant la nuit. C’est bien mieux, car nous avions des centaines de tests avant un seul échec, mais il semble que l’utilisation de ROWDEPENDENCIES n’est pas encore une solution complète.
J'ai une solution de contournement pour ce problème.
Suivez l'étape ci-dessous.
BATCH_JOB_INSTANCE
, BATCH_JOB_EXECUTION
et BATCH_JOB_EXECUTION_PARAMS
. (n'oubliez pas de vous engager)J'ai pu résoudre cette erreur en ajoutant isolationLevelForCreate comme ci-dessous:
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<property name="databaseType" value="Oracle"/>
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="isolationLevelForCreate" value="ISOLATION_READ_UNCOMMITTED"/>
</bean>