Java SpringBoot defining multiple datasources error - postgresql

I am using springBoot, and am following this tutorial while trying to set up two datasources (pims & powwow).
application.properties
# pims datasource
spring.datasource1.jdbc-url=jdbc:postgresql://localhost:5432/pims
spring.datasource1.username=postgres
spring.datasource1.password=postgres
# powwow datasource
spring.datasource2.jdbc-url=jdbc:postgresql://localhost:5432/powwow
spring.datasource2.username=postgres
spring.datasource2.password=postgres
PersistencePimsAutoConfiguration.java
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = {"com.clubtravel.powwow.dao.pims", "com.clubtravel.powwow.repositories.pims"},
entityManagerFactoryRef = "pimsEntityManager",
transactionManagerRef = "pimsTransactionManager")
public class PersistencePimsAutoConfiguration {
#Autowired
private Environment env;
#Primary
#Bean
#ConfigurationProperties(prefix="spring.datasource1")
public DataSource pimsDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
public LocalContainerEntityManagerFactoryBean pimsEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(pimsDataSource());
em.setPackagesToScan(new String[] { "com.clubtravel.powwow.entities.pims" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public PlatformTransactionManager pimsTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(pimsEntityManager().getObject());
return transactionManager;
}
}
PersistencePowwowAutoConfiguration.java
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = {"com.clubtravel.powwow.dao.powwow", "com.clubtravel.powwow.repositories.powwow"},
entityManagerFactoryRef = "powwowEntityManager",
transactionManagerRef = "powwowTransactionManager")
public class PersistencePowwowAutoConfiguration {
#Autowired
private Environment env;
#Primary
#Bean
#ConfigurationProperties(prefix="spring.datasource2")
public DataSource powwowDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean powwowEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(powwowDataSource());
em.setPackagesToScan(new String[] { "com.clubtravel.powwow.entities.powwow" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public PlatformTransactionManager powwowTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(powwowEntityManager().getObject());
return transactionManager;
}
}
LobDao.java
#Component
public class LobDao {
#Autowired
LobRepository lobRepository;
#PersistenceContext
EntityManager entityManager;
public List<LobEntity> findAll() {
return lobRepository.findAll();
}
LobRepository.java
#Repository
public interface LobRepository extends JpaRepository<LobEntity,Integer> {
}
When i start the server, I get the folowing:
Error
***************************
APPLICATION FAILED TO START
***************************
Description:
Field lobRepository in com.clubtravel.powwow.dao.pims.LobDao required a bean of type 'com.clubtravel.powwow.repositories.pims.LobRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.clubtravel.powwow.repositories.pims.LobRepository' in your configuration.
I have partitioned the entities, daos and repositories for each separate database.
More info:
If I add the repository package:
basePackages = {"com.clubtravel.powwow.dao.pims", "com.clubtravel.powwow.repositories.pims"},
The error becomes:
Description:
Field lobRepository in com.clubtravel.powwow.dao.pims.LobDao required a bean named 'pimsEntityManager' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean named 'pimsEntityManager' in your configuration.
More info:
I have also tried adding '#Transactional' to the DAO, but it makes no difference:
#Transactional("pimsTransactionManager")
public List<LobEntity> findAll() {
return lobRepository.findAll();
}

I had such problem, and it resolved by just adding these annotationsannotations in the main springBoot application class:
#SpringBootApplication(scanBasePackages = "com.clubtravel.powwow")
#EntityScan("com.clubtravel.powwow")
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

Related

Springboot #Transactional annotation not working with datasource

I am trying to configure springBoot to have 2 datasources ('pims' & 'powwow') by following this tutorial.
It kind of works, but only for the #Primary datasource. How do I get it to work for the other datasource?
application.properties
# pims datasource
spring.datasource1.driver-class-name=org.postgresql.Driver
spring.datasource1.jdbc-url=jdbc:postgresql://localhost:5432/pims
spring.datasource1.username=postgres
spring.datasource1.password=postgres
# powwow datasource
spring.datasource2.driver-class-name=org.postgresql.Driver
spring.datasource2.jdbc-url=jdbc:postgresql://localhost:5432/powwow
spring.datasource2.username=postgres
spring.datasource2.password=postgres
PersistencePimsAutoConfiguration.java
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = {"com.clubtravel.powwow.dao.pims", "com.clubtravel.powwow.repositories.pims"},
entityManagerFactoryRef = "pimsEntityManager",
transactionManagerRef = "pimsTransactionManager")
public class PersistencePimsAutoConfiguration {
private Logger logger = LogManager.getLogger(PersistencePimsAutoConfiguration.class);
#Value("${spring.datasource1.jdbc-url}")
private String url;
#Value("${spring.datasource1.username}")
private String username;
#Value("${spring.jpa.hibernate.ddl-auto}")
private String hbm2ddl;
#Value("${spring.jpa.database-platform}")
private String platform;
#Value("${spring.jpa.properties.hibernate.dialect}")
private String dialect;
#Value("${spring.profiles.active}")
private String profile;
#Bean
#ConfigurationProperties(prefix="spring.datasource1")
public DataSource pimsDataSource() {
return DataSourceBuilder.create().build();
}
//#Bean(name = "pimsEntityManager")
#Bean
public LocalContainerEntityManagerFactoryBean pimsEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(pimsDataSource());
em.setPackagesToScan(new String[] {"com.clubtravel.powwow.entities.pims"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", hbm2ddl);
properties.put("hibernate.dialect", dialect);
em.setJpaPropertyMap(properties);
String host = null;
try {
host = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
logger.info("Setting spring.datasource1 (pims): hibernate.hbm2ddl.auto='"+hbm2ddl+"', platform='"+platform+"', url='"+url+"', username='"+username+"', host='"+host+"', profile='"+profile+"'.");
return em;
}
#Bean
public PlatformTransactionManager pimsTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(pimsEntityManager().getObject());
return transactionManager;
}
}
PersistencePowwowAutoConfiguration.java
#Configuration
#PropertySource({"classpath:application.properties"})
#EnableJpaRepositories(
basePackages = {"com.clubtravel.powwow.dao.powwow", "com.clubtravel.powwow.repositories.powwow"},
entityManagerFactoryRef = "powwowEntityManager",
transactionManagerRef = "powwowTransactionManager")
public class PersistencePowwowAutoConfiguration {
private Logger logger = LogManager.getLogger(PersistencePowwowAutoConfiguration.class);
#Value("${spring.datasource2.jdbc-url}")
private String url;
#Value("${spring.datasource2.username}")
private String username;
#Value("${spring.jpa.hibernate.ddl-auto}")
private String hbm2ddl;
#Value("${spring.jpa.database-platform}")
private String platform;
#Value("${spring.jpa.properties.hibernate.dialect}")
private String dialect;
#Value("${spring.profiles.active}")
private String profile;
#Bean
#Primary
#ConfigurationProperties(prefix="spring.datasource2")
public DataSource powwowDataSource() {
return DataSourceBuilder.create().build();
}
//#Bean(name = "powwowEntityManager")
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean powwowEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(powwowDataSource());
em.setPackagesToScan(new String[] { "com.clubtravel.powwow.entities.powwow" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", hbm2ddl);
properties.put("hibernate.dialect", dialect);
em.setJpaPropertyMap(properties);
String host = null;
try {
host = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
logger.info("Setting spring.datasource2 (powwow): hibernate.hbm2ddl.auto='"+hbm2ddl+"', platform='"+platform+"', url='"+url+"', username='"+username+"', host='"+host+"', profile='"+profile+"'.");
return em;
}
#Bean
#Primary
public PlatformTransactionManager powwowTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(powwowEntityManager().getObject());
return transactionManager;
}
}
I thought that when I used the secondary datasource, if I added the #Trannsactional annotation, it would work.
e.g.
MerchantsDao.java
#Transactional("pimsTransactionManager")
public List<MerchantsEntity> findByCustomerNumber(String customerNumber) {
Query qry = entityManager.createNamedQuery("Merchants.findByCustomerNo");
qry.setParameter(1, customerNumber);
List<MerchantsEntity> entities = (List<MerchantsEntity>) qry.getResultList();
return entities;
}
However, it says it cannot find the query:
java.lang.IllegalArgumentException: No query defined for that name
[Merchants.findByCustomerNo]
I also try adding #Transactional("pimsTransactionManager") at the DAO's class level, but still get the same error above. If I switch the #Primary annotation to the 'pimsTransactionManager' datasource beans, then that datasources works but the 'powwowTransactionManager' datasource gets this error.
So it looks like even though I define two datasources, it only works with the primary one.

Multithreading with StoredProcedureItemReader

Is it possible to have multiple threads with StoredProcedureItemReader? I have done multithreading with PageReader but not sure if it will work with StoredProcedureItemReader.
Below is the job configuration for using a StoredProcedureReader. I have wrapped the reader in Thread safe reader. I want to use ThreadPoolTaskExecutor but not able to figure out how I can do partition for each thread with the Stored procedure.
***#Configuration
public class SpPocJobConfigurationMT {
private DataSource dataSource;
/**
* The Job builder factory.
*/
private JobBuilderFactory jobBuilderFactory;
/**
* The Jdbc template.
*/
#Autowired
JdbcTemplate jdbcTemplate;
/**
* The Step builder factory.
*/
private StepBuilderFactory stepBuilderFactory;
#Autowired
private BillingRecordAuditRepository billingRecordAuditRepository;
#Autowired
private StagingMortgageDataTxnRepository stagingMortgageDataTxnRepository;
private SystemRepository systemRepository;
#Autowired
public SpPocJobConfigurationMT(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, SystemRepository systemRepository, DataSource dataSource) {
Assert.notNull(systemRepository, "SystemRepository cannot be null");
Assert.notNull(jobBuilderFactory, "JobBuilderFactory cannot be null");
Assert.notNull(stepBuilderFactory, "StepBuilderFactory cannot be null");
Assert.notNull(dataSource, "DataSource cannot be null");
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
this.systemRepository = systemRepository;
this.dataSource = dataSource;
}
#Bean
#Transactional
#Description(value = "")
public Job SpPocJobMT() throws Exception {
return jobBuilderFactory.get("spPocJobMT")
.start(spPocStepMT())
.build();
}
#Bean
public Step spPocStepMT() throws Exception {
return stepBuilderFactory.get("spPocStepMT")
.allowStartIfComplete(false)
.<StagingDataDto,StagingDataDto> chunk(20)
.reader(sybcSpReaderMT())
.processor(spPocProcessorMT())
.writer(spPocWriterMT())
// .taskExecutor(new ThreadPoolTaskExecutor ())
// .taskExecutor(new SimpleAsyncTaskExecutor())
.build();
}
#Bean
public SpPocWriter spPocWriterMT() {
return new SpPocWriter(this.billingRepository, this.stagingTxnRepository);
}
#Bean
public SpPocProcessor spPocProcessorMT() {
return new SpPocProcessor();
}
#Bean
#StepScope
public SynchronizedItemStreamReader sybcSpReaderMT() {
StoredProcedureItemReader reader = new StoredProcedureItemReader();
SqlParameter[] parameters = {new SqlParameter("#p_id", OracleTypes.NUMBER)
, new SqlOutParameter("#p_out_c1", OracleTypes.CURSOR)
, new SqlOutParameter("#p_out_c2", OracleTypes.CURSOR)
};
reader.setDataSource(dataSource);
reader.setProcedureName("SP_POC_FINAL");
reader.setRowMapper(new SPRowMapper());
reader.setRefCursorPosition(3);
reader.setPreparedStatementSetter(new MyItemPreparedStatementSetter());
reader.setParameters(parameters);
reader.setSaveState(false);
reader.setVerifyCursorPosition(false);
SynchronizedItemStreamReader synchronizedItemStreamReader = new SynchronizedItemStreamReader();
synchronizedItemStreamReader.setDelegate(reader);
return synchronizedItemStreamReader;
}
public class MyItemPreparedStatementSetter implements PreparedStatementSetter {
#Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setInt(1, 1);
((CallableStatement) ps).registerOutParameter(2, OracleTypes.CURSOR);
((CallableStatement) ps).registerOutParameter(3, OracleTypes.CURSOR);
}
}
}***
The StoredProcedureItemReader extends AbstractItemCountingItemStreamItemReader which is not thread-safe, please check its javadoc.
If you want to use the StoredProcedureItemReader in a multi-threaded step, you need to wrap it in a SynchronizedItemStreamReader or make it step-scoped.

How do I access the datasource in this set up

I have the following application where I am connecting to two databases, therefore two config files. In each of the config files, I define a jdbctemplate which is then injected to the appropriate dao class.
Here are config for the first database
#Configuration
#PropertySource({ "classpath:g1-g2-datasource.properties" })
#EnableJpaRepositories(
basePackages = "com.xyz.vantage.dao.g1",
entityManagerFactoryRef = "g1EntityManager",
transactionManagerRef = "g1TransactionManager"
)
public class SMSDBConfig {
#Primary
#Bean
public DataSource g1DataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("g1.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("g1.datasource.url"));
dataSource.setUsername(env.getProperty("g1.datasource.username"));
dataSource.setPassword(env.getProperty("g1.datasource.password"));
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
return jdbcTemplate;
}
This is the config file with config file for the second database.
#Configuration
#PropertySource({ "classpath:g1-g2-datasource.properties" })
#EnableJpaRepositories(
basePackages = "com.xyz.vantage.dao.g2",
entityManagerFactoryRef = "g2EntityManager",
transactionManagerRef = "g2TransactionManager"
)
public class Griffin2DBConfig {
#Bean(name="g2DataSource")
public DataSource g2DataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("g2.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("g2.datasource.url"));
dataSource.setUsername(env.getProperty("g2.datasource.username"));
dataSource.setPassword(env.getProperty("g2.datasource.password"));
return dataSource;
}
#Bean(name="g2jdbcTemplate")
public JdbcTemplate g2jdbcTemplate(DataSource g2DataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(g2DataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
return jdbcTemplate;
}
}
In my dao class below, I inject the jdbctemplate defined in the second file (g2jdbcTemplate). However this jdbctemplate still gets injected with the first datasource. How do I inject it with the datasource defined in the same file? (#Bean(name="g2DataSource") )
#Autowired
JdbcTemplate g2jdbcTemplate;
#Override
public List<ContainerWithDetails> getContainerMilestones(MilestoneRequest request) {
final List<ContainerWithDetails> g1list = new ArrayList();
g2jdbcTemplate.query("select top 10 * from EQUIP", new RowCallbackHandler() {
#Override
public void processRow(ResultSet resultSet) throws SQLException {
ContainerInfo cInfo = new ContainerInfo();
cInfo.setContainerNo(resultSet.getString("equip_no"));
cInfo.setContanerId(resultSet.getString("equip_id"));
ContainerWithDetails cDetails = new ContainerWithDetails();
cDetails.setContainerInfo(cInfo);
g1list.add(cDetails);
}
});
return g1list;
}

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
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
}
}
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();
}
}
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");
...
}

Spring-boot jpa only can access primary from muliple data sources

Trying to use 2 data sources as below inside spring-boot:
DB configs:
//no primary
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "rwEntityManagerFactory",
transactionManagerRef = "rwTransactionManager",
basePackages = {"com.cvs.dvp.repository.rw"})
#PropertySource("classpath:application.properties")
public class RwDbConfiguration {
#Bean(name="rwDataSource")
//#Primary
#ConfigurationProperties(prefix="datasource.rw")
public DataSource rwDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name="rwEntityManagerFactory")
#Qualifier("rwEntityManagerFactory")
public EntityManagerFactory rwEntityManagerFactory() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setGenerateDdl(false);
jpaVendorAdapter.setDatabase(Database.ORACLE);
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(rwDataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.cvs.dvp.domain.rw");
lef.setPersistenceUnitName("rw");
lef.afterPropertiesSet();
return lef.getObject();
}
#Bean(name="rwTransactionManager")
#Qualifier("rwTransactionManager")
public JpaTransactionManager transactionManager(#Qualifier("rwEntityManagerFactory")EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
And //primary
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "dsEntityManagerFactory",
transactionManagerRef = "dsTransactionManager",
basePackages = {"com.cvs.dvp.repository.dsd"})
#PropertySource("classpath:application.properties")
public class DsdDbConfiguration {
#Bean(name="dsDataSource")
#Primary
#ConfigurationProperties(prefix="datasource.ds")
public DataSource dsDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name="dsEntityManagerFactory")
#Qualifier("dsEntityManagerFactory")
public EntityManagerFactory dsEntityManagerFactory( ) {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setDatabase(Database.ORACLE);
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dsDataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.cvs.dvp.domain.dsd");
lef.setPersistenceUnitName("dsd");
lef.afterPropertiesSet();
return lef.getObject();
}
#Bean(name="dsTransactionManager")
#Qualifier("dsTransactionManager")
#Primary
public JpaTransactionManager transactionManager(#Qualifier("dsEntityManagerFactory")EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
The services are:
#Service
public class ReceiptServiceImpl implements ReceiptService {
private static final Logger LOGGER = LoggerFactory.getLogger(ReceiptServiceImpl.class);
private final ReceiptRepository repository;
#Autowired
#PersistenceContext(unitName = "rw")
#Qualifier("rwTransactionManager")
private JpaTransactionManager jpaTransactionManager;
#Inject
public ReceiptServiceImpl(final ReceiptRepository repository) {
this.repository = repository;
}
#Override
#Transactional("rwTransactionManager")
public Receipt save(#NotNull #Valid final Receipt receipt) {
EntityManagerFactory emf = jpaTransactionManager.getEntityManagerFactory();
EntityManager entityManager = emf.createEntityManager();
LOGGER.debug("Creating {}", receipt.getId());
Receipt existing = repository.findOne(receipt.getStoreNumber());
if (existing != null) {
throw new UserAlreadyExistsException(
String.format("There already exists a receipt with id=%s", receipt.getId()));
}
return repository.save(existing);
}
#Override
#Transactional("rwTransactionManager")
public List<Receipt> getList() {
LOGGER.debug("Retrieving the list of all users");
return repository.findAll();
}
#Override
#Transactional("rwTransactionManager")
public Receipt getOne(String storeNumber) {
return repository.findOne(storeNumber);
}
}
And
#Service
#Validated
public class StatusServiceImpl implements StatusService {
private static final Logger LOGGER = LoggerFactory.getLogger(StatusServiceImpl.class);
private final StatusRepository repository;
#Autowired
#Qualifier("dsTransactionManager")
private JpaTransactionManager jpaTransactionManager;
#Inject
public StatusServiceImpl(final StatusRepository repository) {
this.repository = repository;
}
#Override
#Transactional
public Status save(#NotNull #Valid final Status status) {
EntityManagerFactory emf = jpaTransactionManager.getEntityManagerFactory();
EntityManager entityManager = emf.createEntityManager();
LOGGER.debug("Creating {}", status);
Status existing = repository.findOne(status.getStatusCd());
if (existing != null) {
throw new UserAlreadyExistsException(
String.format("There already exists a user with id=%s", status.getStatusCd()));
}
return repository.save(status);
}
#Override
#Transactional
public List<Status> getList() {
LOGGER.debug("Retrieving the list of all users");
return repository.findAll();
}
}
The issue: bean wiring is ok, but only primary datasource can be accessed, another datasource got "table or view does not existed" error, but if it been configed as primary everything works fine and previous primary datasource will not be accessable.
Tried to make none of them primary as post Multiple jpa:repositories in xml config, how to configure with #EnableJPARepositories using Spring java config?, but would not pass spring-boot compiler.
Spring CLI version is 1.2.1.
Appreciate your help.