70140

How to run update query in Spring JPA for quartz job

I have a quartz job in spring 4 and I am using JPA hibernate to update database value through quartz job but I am getting javax.persistence.TransactionRequiredException: Executing an update/delete query

I don't understand what kind of configuration is missing in quartz job. I referred to SpringBeanAutowiringSupport example still update is failing but select is working fine.

Below is my code

@Configuration @ComponentScan("com.stock") public class QuartzConfiguration { @Autowired private ApplicationContext applicationContext; @Bean public JobDetailFactoryBean jobDetailBalanceCarryForward(){ JobDetailFactoryBean factory = new JobDetailFactoryBean(); factory.setJobClass(BillingCroneSvcImpl.class); Map<String,Object> map = new HashMap<String,Object>(); map.put("task", "balanceCarryForward"); factory.setJobDataAsMap(map); factory.setGroup("BalanceCarryForwardJob"); factory.setName("balance carry forward"); return factory; } @Bean public CronTriggerFactoryBean cronTriggerBalanceCarryForward(){ CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean(); stFactory.setJobDetail(jobDetailBalanceCarryForward().getObject()); stFactory.setStartDelay(3000); stFactory.setName("balancCarryForwardTrigger"); stFactory.setGroup("balanceCarryForwardgroup"); stFactory.setCronExpression("0 0/1 * 1/1 * ? *"); return stFactory; } @Bean public SpringBeanJobFactory springBeanJobFactory() { AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); schedulerFactory.setJobFactory(springBeanJobFactory()); schedulerFactory.setTriggers(cronTriggerBalanceCarryForward().getObject()); return schedulerFactory; } }

Below class where quartz executeInternal method is written

@Service @PersistJobDataAfterExecution @DisallowConcurrentExecution @Autowired private BillingCroneRepo billingCroneRepo; public class BillingCroneSvcImpl extends QuartzJobBean implements BillingCroneSvc { @Override @Transactional protected void executeInternal(JobExecutionContext context) throws JobExecutionException { SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(context); billingCroneRepo.updateBalance(); // this method throws exception javax.persistence.TransactionRequiredException: Executing an update/delete query } }

App config class

@EnableWebMvc @EnableTransactionManagement @Configuration @ComponentScan({ "com.stock.*" }) @Import({ SecurityConfig.class }) @PropertySource("classpath:jdbc.properties") public class AppConfig extends WebMvcConfigurerAdapter { private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver"; private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password"; private static final String PROPERTY_NAME_DATABASE_URL = "db.url"; private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username"; private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect"; private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql"; private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan"; @Resource private Environment env; @Bean(name = "dataSource") public DriverManagerDataSource dataSource() { DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(); driverManagerDataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER)); driverManagerDataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL)); driverManagerDataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME)); driverManagerDataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD)); return driverManagerDataSource; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource()); entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class); entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN)); entityManagerFactoryBean.setJpaProperties(hibProperties()); return entityManagerFactoryBean; } private Properties hibProperties() { Properties properties = new Properties(); properties.put(PROPERTY_NAME_HIBERNATE_DIALECT,env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT)); properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL,env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL)); return properties; } @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory().getObject()); return transactionManager; } @Bean public ReloadableResourceBundleMessageSource messageSource(){ ReloadableResourceBundleMessageSource messageSource=new ReloadableResourceBundleMessageSource(); String[] resources= {"classpath:messages"}; messageSource.setBasenames(resources); return messageSource; } @Bean public LocaleResolver localeResolver() { final CookieLocaleResolver ret = new CookieLocaleResolver(); ret.setDefaultLocale(new Locale("en_IN")); return ret; } @Bean public LocaleChangeInterceptor localeChangeInterceptor(){ LocaleChangeInterceptor localeChangeInterceptor=new LocaleChangeInterceptor(); localeChangeInterceptor.setParamName("language"); return localeChangeInterceptor; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/Angular/**").addResourceLocations("/Angular/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); registry.addResourceHandler("/email_templates/**").addResourceLocations("/email_templates/"); registry.addResourceHandler("/fonts/**").addResourceLocations("/fonts/"); registry.addResourceHandler("/img/**").addResourceLocations("/img/"); registry.addResourceHandler("/js/**").addResourceLocations("/js/"); registry.addResourceHandler("/Landing_page/**").addResourceLocations("/Landing_page/"); } @Bean public static PropertySourcesPlaceholderConfigurer properties() { PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer(); org.springframework.core.io.Resource[] resources = new ClassPathResource[] { new ClassPathResource("application.properties") }; pspc.setLocations(resources); pspc.setIgnoreUnresolvablePlaceholders(true); return pspc; } @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } // through below code we directly read properties file in jsp file @Bean(name = "propertyConfigurer") public PropertiesFactoryBean mapper() { PropertiesFactoryBean bean = new PropertiesFactoryBean(); bean.setLocation(new ClassPathResource("application.properties")); return bean; } }

Can anybody please assist me how to resolve transational issue in spring JPA with quartz

Answer1:

Thanks you all for your help. Finally I autowired EntityManagerFactory instead of persitance EntityManager and it is working fine. I tried all scenario but nothing worked to inject spring transactional in quartz so finally autoriwed entitymanagerfactory

Below is my repo class code.

@Repository public class BillingCroneRepoImpl implements BillingCroneRepo { /*@PersistenceContext private EntityManager entityManager;*/ @Autowired EntityManagerFactory entityManagerFactory; public boolean updateTable(){ EntityManager entityManager = entityManagerFactory.createEntityManager(); EntityTransaction entityTransaction = entityManager.getTransaction(); entityTransaction.begin(); // this will go in try catch Query query = entityManager.createQuery(updateSql); // update table code goes here entityTransaction.commit(); // this will go in try catch } }

Answer2:

I'm not the Spring specialist, but I think new ... doesn't work with @Transactional

@Service @PersistJobDataAfterExecution @DisallowConcurrentExecution public class BillingCroneSvcImpl extends QuartzJobBean implements BillingCroneSvc { @Autowired BillingCroneRepo billingCroneRepo; @Override @Transactional protected void executeInternal(JobExecutionContext context) throws JobExecutionException { SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(context); billingCroneRepo.updateBalance(); } }

Answer3:

It's because quartz is using the bean instead of the proxy generated for @Transactional.

Use either MethodInvokingJobDetailFactoryBean (instead of inheriting QuartzJob) or use a dedicated wrapper quarz bean (inheriting from QuartzJob) that call the spring bean (not inheriting from QuartzJob) having the @Transactionnal annotation.

EDIT : this is in fact not the problem

The problem is here :

JobDetailFactoryBean factory = new JobDetailFactoryBean(); factory.setJobClass(BillingCroneSvcImpl.class);

By passing the class, I presume that Quartz will instantiate it itself, so Spring won't create it and won't wrap the bean in a Proxy that handle the @Transactionnal behaviour.

Instead you must use something along the line :

@Bean(name = "billingCroneSvc") public BillingCroneSvc getSvc(){ return new BillingCroneSvcImpl(); } @Bean public JobDetailFactoryBean jobDetailBalanceCarryForward(){ JobDetailFactoryBean factory = new JobDetailFactoryBean(); getSvc();// just make sure the bean is instantiated factory.setBeanName("billingCroneSvc"); ... }

Recommend

  • Spring instantiates bean but can't use it
  • stored procedures and banks
  • How to call Service in Grails with groovy
  • One transaction for several JpaRepositories' methods
  • Is it good to have multiple database running in a same project?
  • Grails Cannot get property 'id' on null object
  • NativeQuery Spring Data return object
  • Is it mandatory to have a doGet or doPost method?
  • Swift Initialization Rule Confusion
  • Change Checkbox value without raising event
  • LiveData is abstract android
  • CSS - Cannot get one spanned style to override another inherited style and align left
  • Authentication failed with Azure Active Directory in Windows Phone
  • How to get listview position?
  • Regarding starting the threads on a condition
  • Spring: No transaction manager has been configured
  • JPA flush vs commit
  • Elasticsearch script query involving root and nested values
  • Center align outputs in ipython notebook
  • Why use database factory in asp.net mvc?
  • Android Activity.onWindowFocusChanged doesn't get called from within TabHost
  • Zoom in and out of jPanel
  • How do I configure context broker accept post requests from my remote sensor?
  • Creating Java object from class name with constructor, which contains parameters [duplicate]
  • GridView breaks while scrolling
  • How to use RequestBodyAdvice
  • NHibernate Validation Localization with S#arp Architecture
  • how to do an event when i swipe from fragment to the other
  • Update CALayer sublayers immediately
  • JFileChooser in front of fullscreen Swing application
  • Array.prototype.includes - not transformed with babel
  • Javascript Callbacks with Object constructor
  • unknown Exception android
  • failed to connect to specific WiFi in android programmatically