Pros and cons of changing autocommit=true in spring boot application? - spring-boot

To me it looks like autocommit is completely overridden with Spring-Hibernate configuration and this property absolutely doesn't play any role in such a configuration but I would like to confirm that somehow.
Spring boot 1.5.10.RELEASE version. Database is PostgreSQL 9.5.6.
Datasource configuration
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.persistence.EntityManagerFactory;
import java.util.Properties;
#Configuration
public class DataSourceConfig {
private Logger logger = LoggerFactory.getLogger(DataSourceConfig.class);
#Bean(name = "dataSource")
public DriverManagerDataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName(driver);
driverManagerDataSource.setUrl(url);
driverManagerDataSource.setUsername(username);
driverManagerDataSource.setPassword(password);
return driverManagerDataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { domainModelNamespace });
em.setJpaProperties(additionalProperties());
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.show_sql", showSql);
properties.setProperty("hibernate.dialect", dialect);
properties.setProperty("hibernate.hbm2ddl.auto", hbm2ddl);
return properties;
}
}
And here is test method
import com.phonebook.IntegrationTest;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.sql.DataSource;
import java.sql.SQLException;
public class DataSourceTesting extends IntegrationTest{
#Autowired
private DataSource dataSource;
Logger logger = LoggerFactory.getLogger(DataSourceTesting.class);
#Test
public void testDataSourceConnectionProperties() throws SQLException {
boolean autoCommit = dataSource.getConnection().getAutoCommit();
Assert.assertFalse(autoCommit);
}
}
The question is what autocommit means in this context? In test it is on
true
as well as in #Transactional method checking it in debug mode.

Related

Rollback is not working in #Transactional annotated service. Spring + Hibernate

In my code the service method savePerson is annotated with #Transactional. Inside this method a Person entity is persisted and inmediately a Runtime exception is intentionally throwed. I suposse the transaction should not be commited but the Person entity is persisted in database....rollback is not working and I dont know why.
This is my Hibernate Configuration:
package newp;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
public class HibernateConf {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[]{"newp"});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/poas");
dataSource.setUsername("admin");
dataSource.setPassword("admin");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager= new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
return hibernateProperties;
}
}
This is my service:
package newp.services;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import newp.dao.PersonDao;
import newp.model.Person;
#Service
public class PersonService{
#Autowired
PersonDao dao;
#Transactional
public void savePerson(Person p) {
dao.savePerson(p);
throw new RuntimeException();
}
}
The DAO
package newp.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import newp.entities.PersonEntity;
import newp.model.Person;
#Repository
public class PersonDao {
#Autowired
SessionFactory sessionFactory;
public void savePerson(Person person) {
Session s = sessionFactory.getCurrentSession();
PersonEntity p=new PersonEntity();
p.setAge(person.getAge());
p.setName(person.getName());
p.setSurname(person.getSurname());
s.saveOrUpdate(p);
}
}
You are probably using tables with the MyISAM storage engine which does not support transactions: https://stackoverflow.com/a/8036049/412446

Spring Boot JPA Custom Datasource for Native Query

I am using two different databases in my Spring Boot Application , i have defined two different configurations for each database:
DB1
#Configuration
#EnableJpaRepositories(basePackages = {
"com.company.bod.repositries.db1" }, entityManagerFactoryRef = "db1EntityManager", transactionManagerRef = "db1TransactionManager")
public class db1DBDatasource {
#Autowired
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean db1EntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(db1Datasource());
em.setPackagesToScan(new String[]{"com.company.bod.entities.db1"});
em.setPersistenceUnitName("db1EntityManager");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
properties.put("hibernate.show-sql",env.getProperty("jdbc.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public DataSource db1Datasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.db1-datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.db1-datasource.jdbc-url"));
dataSource.setUsername(env.getProperty("spring.db1-datasource.username"));
dataSource.setPassword(env.getProperty("spring.db1-datasource.password"));
return dataSource;
}
#Bean
public PlatformTransactionManager db1TransactionManager() {
JpaTransactionManager transactionManager= new JpaTransactionManager();
transactionManager.setEntityManagerFactory( db1EntityManager().getObject());
return transactionManager;
}
}
DB2
package com.company.bod.config.db;
import java.util.HashMap;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
#Configuration
#EnableJpaRepositories(basePackages = {
"com.company.bod.repositries.bodtracker" }, entityManagerFactoryRef = "db2EntityManager", transactionManagerRef = "db2TransactionManager")
public class db2DataSource {
#Autowired
private Environment env;
#Primary
#Bean
public LocalContainerEntityManagerFactoryBean db2EntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(db2Datasource());
em.setPackagesToScan(new String[]{"com.company.bod.entities.bodtracker"});
em.setPersistenceUnitName("db2EntityManager");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<String, Object>();
// HashMap<string, object=""> properties = new HashMap<>();
properties.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
properties.put("hibernate.show-sql",env.getProperty("jdbc.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource db2Datasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.second-datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.second-datasource.jdbc-url"));
dataSource.setUsername(env.getProperty("spring.second-datasource.username"));
dataSource.setPassword(env.getProperty("spring.second-datasource.password"));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager db2TransactionManager() {
JpaTransactionManager transactionManager= new JpaTransactionManager();
transactionManager.setEntityManagerFactory( db2EntityManager().getObject());
return transactionManager;
}
}
Now i have created a new Custom Service under the package
com.company.bod.repositries.db1
package com.company.bod.repositries.db1;
import java.util.List;
import com.company.bod.entities.crm.CRMAttributes;
public interface NativeRepositryCustom {
public List<CRMAttributes> getAttributesbyId(String id, List<String> names );
}
Impl Class
package com.company.bod.repositries.db1;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import com.company.bod.entities.crm.CRMAttributes;
#Repository
public class CustomNativeRepositoryImpl implements NativeRepositryCustom{
#PersistenceContext
private EntityManager entityManager;
#Override
public List<CRMAttributes> getAttributesbyFullfillOrderId(String fullfillorderid, List<String> names ) {
String q = "SELECT " +
" name, `value` " +
"FROM crmord.tbl_fulfill_order_prop " +
"where name IN (:names) " +
"AND fulfill_order_id=:orderid";
Query query = entityManager.createNativeQuery(q);
query.setParameter("names", names);
query.setParameter("orderid", fullfillorderid);
List<CRMAttributes> list = query.getResultList();
return list;
}
}
but when i try to use CustomNativeRepositoryImpl application complaints about the table found. I am assuming this is due to db1 not being primary . How can i tell CustomNativeRepositoryImpl to use db1 datasource.
I have tried below but it didnt work:
package com.company.bod.repositries.db1;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import com.company.bod.entities.crm.CRMAttributes;
#Repository
public class CustomNativeRepositoryImpl implements NativeRepositryCustom{
#PersistenceContext
private EntityManager entityManager;
#Qualifier("CrmDBDatasource")
DataSource dataSource;
#Override
public List<CRMAttributes> getAttributesbyFullfillOrderId(String fullfillorderid, List<String> names ) {
String q = "SELECT " +
" name, `value` " +
"FROM crmord.tbl_fulfill_order_prop " +
"where name IN (:names) " +
"AND fulfill_order_id=:orderid";
Query query = entityManager.createNativeQuery(q);
query.setParameter("names", names);
query.setParameter("orderid", fullfillorderid);
List<CRMAttributes> list = query.getResultList();
return list;
}
}
I went on to create an Entity with only required columns for the tbl_fulfill_order_prop and then interface using JPA Repository .

Spring Batch ResourcelessTransactionManager messes with persistence.xml?

I am working on an application and have been asked to implement a scheduled spring batch job. I have set up a configuration file where I set a #Bean ResourcelessTransactionManager but it seems to mess with the persistence.xml.
There is already a persistence xml in an other module, there is no compilation error. I get a NoUniqueBeanDefinitionException when I am requesting a page that returns a view item.
This is the error:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: txManager,transactionManager
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:366)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:271)
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.mypackage.services.MyClassService$$EnhancerBySpringCGLIB$$9e8bf16f.registryEvents(<generated>)
at com.mypackage.controllers.MyClassSearchView.init(MyClassSearchView.java:75)
... 168 more
Is there a way to tell spring batch to use the data source defined in the persistence.xml of the other module or maybe is this caused by something else?
I created separate BatchScheduler java class as below and included it in BatchConfiguration java class. I am sharing both the classes. BatchConfiguration contains another jpaTransactionManager.
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
#Configuration
#EnableScheduling
public class BatchScheduler {
#Bean
public ResourcelessTransactionManager resourcelessTransactionManager() {
return new ResourcelessTransactionManager();
}
#Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(
ResourcelessTransactionManager resourcelessTransactionManager) throws Exception {
MapJobRepositoryFactoryBean factory = new
MapJobRepositoryFactoryBean(resourcelessTransactionManager);
factory.afterPropertiesSet();
return factory;
}
#Bean
public JobRepository jobRepository(
MapJobRepositoryFactoryBean factory) throws Exception {
return factory.getObject();
}
#Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
return launcher;
}
}
BatchConfiguration contains another jpaTransactionManager.
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.transaction.PlatformTransactionManager;
import trade.api.common.constants.Constants;
import trade.api.entity.SecurityEntity;
import trade.api.trade.batch.item.processor.SecurityItemProcessor;
import trade.api.trade.batch.item.reader.NseSecurityReader;
import trade.api.trade.batch.notification.listener.SecurityJobCompletionNotificationListener;
import trade.api.trade.batch.tasklet.SecurityReaderTasklet;
import trade.api.vo.SecurityVO;
#Configuration
#EnableBatchProcessing
#EnableScheduling
#Import({OhlcMonthBatchConfiguration.class, OhlcWeekBatchConfiguration.class, OhlcDayBatchConfiguration.class, OhlcMinuteBatchConfiguration.class})
public class BatchConfiguration {
private static final String OVERRIDDEN_BY_EXPRESSION = null;
/*
Load the properties
*/
#Value("${database.driver}")
private String databaseDriver;
#Value("${database.url}")
private String databaseUrl;
#Value("${database.username}")
private String databaseUsername;
#Value("${database.password}")
private String databasePassword;
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
private JobLauncher jobLauncher;
#Bean
public TaskScheduler taskScheduler() {
return new ConcurrentTaskScheduler();
}
//second, minute, hour, day of month, month, day(s) of week
//#Scheduled(cron = "0 0 21 * * 1-5") on week days
#Scheduled(cron="${schedule.insert.security}")
public void importSecuritySchedule() throws Exception {
System.out.println("Job Started at :" + new Date());
JobParameters param = new JobParametersBuilder().addString("JobID",
String.valueOf(System.currentTimeMillis())).toJobParameters();
JobExecution execution = jobLauncher.run(importSecuritesJob(), param);
System.out.println("Job finished with status :" + execution.getStatus());
}
#Bean SecurityJobCompletionNotificationListener securityJobCompletionNotificationListener() {
return new SecurityJobCompletionNotificationListener();
}
//Import Equity OHLC End
//Import Equity Start
// tag::readerwriterprocessor[]
#Bean
public SecurityReaderTasklet securityReaderTasklet() {
return new SecurityReaderTasklet();
}
#Bean
#StepScope
public NseSecurityReader<SecurityVO> nseSecurityReader(#Value("#{jobExecutionContext["+Constants.SECURITY_DOWNLOAD_FILE+"]}") String pathToFile) throws IOException {
NseSecurityReader<SecurityVO> reader = new NseSecurityReader<SecurityVO>();
reader.setLinesToSkip(1);
reader.setResource(new FileSystemResource(pathToFile));
reader.setLineMapper(new DefaultLineMapper<SecurityVO>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames(new String[] { "symbol", "nameOfCompany", "series", "dateOfListing", "paidUpValue", "marketLot", "isinNumber", "faceValue" });
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<SecurityVO>() {{
setTargetType(SecurityVO.class);
}});
}});
return reader;
}
#Bean
public SecurityItemProcessor processor() {
return new SecurityItemProcessor();
}
#Bean
public JpaItemWriter<SecurityEntity> writer() {
JpaItemWriter<SecurityEntity> writer = new JpaItemWriter<SecurityEntity>();
writer.setEntityManagerFactory(entityManagerFactory().getObject());
return writer;
}
// end::readerwriterprocessor[]
// tag::jobstep[]
#Bean
public Job importSecuritesJob() throws IOException {
return jobBuilderFactory.get("importSecuritesJob")
.incrementer(new RunIdIncrementer())
.listener(securityJobCompletionNotificationListener())
.start(downloadSecurityStep())
.next(insertSecurityStep())
.build();
}
#Bean
public Step downloadSecurityStep() throws IOException {
return stepBuilderFactory.get("downloadSecurityStep")
.tasklet(securityReaderTasklet())
.build();
}
#Bean
public Step insertSecurityStep() throws IOException {
return stepBuilderFactory.get("insertSecurityStep")
.transactionManager(jpaTransactionManager())
.<SecurityVO, SecurityEntity> chunk(100)
.reader(nseSecurityReader(OVERRIDDEN_BY_EXPRESSION))
.processor(processor())
.writer(writer())
.build();
}
// end::jobstep[]
//Import Equity End
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(databaseDriver);
dataSource.setUrl(databaseUrl);
dataSource.setUsername(databaseUsername);
dataSource.setPassword(databasePassword);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setPackagesToScan("trade.api.entity");
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter());
lef.setJpaProperties(new Properties());
return lef;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.MYSQL);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(false);
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
return jpaVendorAdapter;
}
#Bean
#Qualifier("jpaTransactionManager")
public PlatformTransactionManager jpaTransactionManager() {
return new JpaTransactionManager(entityManagerFactory().getObject());
}
#Bean
public static PropertySourcesPlaceholderConfigurer dataProperties(Environment environment) throws IOException {
String[] activeProfiles = environment.getActiveProfiles();
final PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:application-"+activeProfiles[0]+".properties"));
return ppc;
}
//// Import Security End
}
Problem solved. There was a PlatformTransactionManager bean located in an other configuration file. I set it as #Primary and now the problem is fixed. Thanks everyone for the help.

when using miltiple datasource hibernate envers are not working

When I use only one datasource, hibernate envers are working well(not using any config.java. just set application.properties). But Using multiple datasource(with config.java, same DB, different user), envers are not working and logged oracle error message ORA-00942.
audited table is in DB#1. How can I do?
spring boot 1.5.6
application.properties
#################################
# DataBase #1 (Default)
#################################
spring.datasource.initialize=true
spring.datasource.url=jdbc:oracle:thin:#localhost:1521:orcl
spring.datasource.username=id_1
spring.datasource.password=pw_1
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
#################################
# DataBase #2(Additional)
#################################
db2.datasource.initialize=true
db2.datasource.url=jdbc:oracle:thin:#localhost:1521:orcl
db2.datasource.username=db_2
db2.datasource.password=pw_2
db2.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
config.java
package com.dev;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
#Configuration
public class DataBaseConfig {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource defaultDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "defaultEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(defaultDataSource())
.packages("com.dev.core.**", "com.dev.ext.**")
.build();
}
#Primary
#Bean(name = "defaultTransactionManager")
PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactory(builder).getObject());
}
#Configuration
#EnableJpaRepositories(basePackages= {"com.dev.core.**", "com.dev.ext.**"},
entityManagerFactoryRef = "defaultEntityManagerFactory", transactionManagerRef = "defaultTransactionManager")
static class DefaultJpaRepositoriesConfig {
}
/*Additional Data Source - NCRM*/
#Bean
#ConfigurationProperties(prefix = "db2.datasource")
public DataSource ncrmDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "ncrmEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean ncrmEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(ncrmDataSource())
.packages("com.dev.ext.ncrm.*.domain")
.build();
}
#Bean(name = "ncrmTtransactionManager")
PlatformTransactionManager ncrmTransactionManagerMain(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(ncrmEntityManagerFactory(builder).getObject());
}
#Configuration
#EnableJpaRepositories(
basePackages="com.dev.ext.ncrm.*.repo",
entityManagerFactoryRef = "ncrmEntityManagerFactory",
transactionManagerRef = "ncrmTtransactionManager")
static class ncrmJpaRepositoriesConfig {
}
}
defaultDO.java
package com.dev.core.domain;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;
import org.hibernate.annotations.NamedNativeQuery;
import org.hibernate.envers.AuditTable;
import org.hibernate.envers.Audited;
import lombok.Data;
#Data
#Entity
#Table(name = "tb_category")
#Audited
#AuditTable("tx_category_audit")
public class CategoryDO {
//codes
}
First add hibernate dialect at application.properties file like below for both data source:
spring.datasource.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
spring.secondDatasource.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
Then Please rewrite the configuration like below
package com.multisource.poc.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
public class ApplicationConfiguration {
#Value("${spring.datasource.hibernate.dialect}")
private String oracleDialect;
#Value("${spring.secondDatasource.hibernate.dialect}")
private String postgresDialect;
#Primary
#Bean(name = "oracleDB")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource oracleDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "oracleEM")
public LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", oracleDialect);
LocalContainerEntityManagerFactoryBean emf = builder
.dataSource(oracleDataSource())
.packages("entitypackageOne")
.persistenceUnit("oraclePU")
.build();
emf.setJpaProperties(properties);
return emf;
}
#Bean(name = "postgresDB")
#ConfigurationProperties(prefix = "spring.secondDatasource")
public DataSource postgresDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "postgresEM")
public LocalContainerEntityManagerFactoryBean postgresEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", postgresDialect);
LocalContainerEntityManagerFactoryBean emf = builder
.dataSource(postgresDataSource())
.packages("entitypackageTwo")
.persistenceUnit("postgresPU")
.build();
emf.setJpaProperties(properties);
return emf;
}
}
Now you have two different EntityManager to use. The sample would be like
#Repository
public class OracleDao implements InterOracle {
private EntityManager entityManager;
#Autowired
public OracleDao(#Qualifier("oracleEM") EntityManager entityManager) {
this.entityManager = entityManager;
}
}
#Repository
public class PostgresDao implements InterPostGres{
private static final Logger LOG
= LoggerFactory.getLogger(PostgresDao.class);
private EntityManager entityManager;
#Autowired
public PostgresDao(#Qualifier("postgresEM") EntityManager entityManager) {
this.entityManager = entityManager;
}
}
This is how my application is working using two different datasource.
Does user db_2 / pw_2 have the required permission to access the DB?

Change #PersistenceContext to #PersistenceUnit while running Junit tests

I am using #PersistenceContext as of now and working fine. However the same application need to be used in Junit context as well. I want #PersistenceContext to be changed to #PersistenceUnit in DaoImpl classes when Junit test cases are running. How to do that?
Using the following versions in my application
<springframework.version>4.2.5.RELEASE</springframework.version>
<hibernate.version>5.1.0.Final</hibernate.version>
<hibernate.validator.version>5.2.4.Final</hibernate.validator.version>
<mysql.connector.version>6.0.3</mysql.connector.version>
<junit.version>4.12</junit.version>
Hibernate Configuration is:
package com.rsa.springwebclasses.configuration.db;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ch.qos.logback.classic.Logger;
#Configuration
#EnableTransactionManagement
#PropertySources({
#PropertySource("classpath:hibernate/hibernate.properties"),
#PropertySource("classpath:mysql/mysql.properties")
})
public class HibernateConfiguration {
Logger logger = (Logger) LoggerFactory.getLogger(HibernateConfiguration.class);
#Autowired
Environment env;
private Properties getHibernateProperties() {
Properties hprop = new Properties();
hprop.put("hibernate.dialect", env.getRequiredProperty("mysql.hibernate.dialect"));
hprop.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
hprop.put("hibernate.format_sql", env.getRequiredProperty("hibernate.format_sql"));
logger.info("Hibernate properties: " + hprop.toString());
return hprop;
}
private Properties getMysqlProperties() {
Properties mySqlProp = new Properties();
mySqlProp.put("jdbc.driverClassName", env.getRequiredProperty("mysql.jdbc.driverClassName"));
mySqlProp.put("jdbc.url", env.getRequiredProperty("test.mysql.jdbc.url"));
mySqlProp.put("jdbc.username", env.getRequiredProperty("test.mysql.jdbc.username"));
mySqlProp.put("jdbc.password", env.getRequiredProperty("test.mysql.jdbc.password"));
logger.info("MySQL properties: " + mySqlProp.toString());
return mySqlProp;
}
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
Properties dbProp = this.getMysqlProperties();
dataSource.setDriverClassName(dbProp.getProperty("jdbc.driverClassName"));
dataSource.setUrl(dbProp.getProperty("jdbc.url"));
dataSource.setUsername(dbProp.getProperty("jdbc.username"));
dataSource.setPassword(dbProp.getProperty("jdbc.password"));
logger.info("DataSource object is created.");
return dataSource;
}
#Bean
public PlatformTransactionManager getTransactionManager(EntityManagerFactory emf) {
JpaTransactionManager jtm = new JpaTransactionManager();
jtm.setEntityManagerFactory(emf);
logger.info("PlatformTransactionManager is initialized with JpaTransactionManager");
return jtm;
}
#Bean
public LocalContainerEntityManagerFactoryBean getEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
emfb.setDataSource(getDataSource());
emfb.setPackagesToScan(new String[] {"com.rsa.springwebclasses.model"});
JpaVendorAdapter vendor = new HibernateJpaVendorAdapter();
emfb.setJpaVendorAdapter(vendor);
emfb.setJpaProperties(getHibernateProperties());
logger.info("LocalContainerEntityManagerFactoryBean created: PersistentUnit Name: " + emfb.getJpaVendorAdapter().toString());
return emfb;
}
}
My DaoImpl class is:
package com.rsa.springwebclasses.dao.impl;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import com.rsa.springwebclasses.dao.UserDao;
import com.rsa.springwebclasses.model.User;
import ch.qos.logback.classic.Logger;
#Repository("userDao")
public class UserDaoImpl implements UserDao {
Logger logger = (Logger) LoggerFactory.getLogger(UserDaoImpl.class);
**#PersistenceContext**
EntityManager em;
public List<User> findAllUsers() {
logger.debug("In findAllUsers method.");
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = cb.createQuery(User.class);
Root<User> user = criteria.from(User.class);
criteria.select(user).orderBy(cb.asc(user.get("username")));
logger.debug("Exit findAllUsers method");
return em.createQuery(criteria).getResultList();
}
}
While injecting EntityManager, #PersistenceContext is hard coded. However the same DaoImpl class need to be used for Junit test cases as well. With Junit I prefer to use transaction type as RESOUCE_LOCAL which is possible only with #PersistenceUnit. Is it possible to have a different annotation in DaoImpl class and assign #PersistenceContext or #PersistenceUnit while application is loading or already running?

Resources