I’m building a Spring Boot application that should support various databases engines (MySQL, PostgreSQL, Oracle, SQL Server).
The user will be prompted to select which database it would like to use when installing the application and all tables will be created after this. I think that I should save the user option somewhere and then use it to select the right engine that my application will use to instantiate the repositories.
I googled for some references or best practices that I should follow to implement this but wasn’t able to find (maybe I’m searching the wrong terms - sorry).
Do you have any resource that points me to the right direction?
Thanks a lot!!!
You can refer sample. In sample I use hibernate + spring boot for multiple databases.
You can work by this way:
Step 1: you declare in application.properties info connect of database (mysql, oracle, postgresql)
# MySQL-Database
mysql.db.driver: com.mysql.jdbc.Driver
mysql.db.url: jdbc:mysql://localhost:3306/test
mysql.db.username: root
mysql.db.password: root
mysql.hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
mysql.entitymanager.packagesToScan: com.test.mysql
# postgresql-Database
postgresql.db.driver: org.postgresql.Driver
postgresql.db.url: jdbc:postgresql://localhost:5432/postgres_demo
postgresql.db.username: root
postgresql.db.password:
postgresql.hibernate.dialect: org.hibernate.dialect.PostgreSQLDialect
postgresql.entitymanager.packagesToScan: com.test.postgresql
# Oracle-Database
oracle.db.driver: oracle.jdbc.driver.OracleDriver
oracle.db.url: jdbc:oracle:thin:#localhost:1521:xe
oracle.db.username: root
oracle.db.password:
oracle.hibernate.dialect: org.hibernate.dialect.Oracle10gDialect
oracle.entitymanager.packagesToScan: com.test.oracle
Step 2: In project spring boot you can refer structure project such as:
Step 3 : Implement data source for mysql, oracle, postgresql. you can refer MysqlDatabaseConfig.java, OracleDatabaseConfig.java, PostgresDatabaseConfig.java
package com.test.mysql;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
public class MysqlDatabaseConfig {
#Value("${mysql.db.driver}")
private String DB_DRIVER;
#Value("${mysql.db.password}")
private String DB_PASSWORD;
#Value("${mysql.db.url}")
private String DB_URL;
#Value("${mysql.db.username}")
private String DB_USERNAME;
#Value("${mysql.hibernate.dialect}")
private String HIBERNATE_DIALECT;
#Value("${mysql.entitymanager.packagesToScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
#Bean(name="mysqlDataSource")
#Primary
public DataSource cmrDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
#Bean(name="mysqlSessionFactory")
public LocalSessionFactoryBean crmSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(cmrDataSource());
sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
#Bean(name="mysqlTransactionManager")
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(crmSessionFactory().getObject());
return transactionManager;
}
}
OracleDatabaseConfig.java
package com.test.oracle;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
public class OracleDatabaseConfig {
#Value("${oracle.db.driver}")
private String DB_DRIVER;
#Value("${oracle.db.password}")
private String DB_PASSWORD;
#Value("${oracle.db.url}")
private String DB_URL;
#Value("${oracle.db.username}")
private String DB_USERNAME;
#Value("${oracle.hibernate.dialect}")
private String HIBERNATE_DIALECT;
#Value("${oracle.entitymanager.packagesToScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
#Bean(name="oracleDataSource")
#Primary
public DataSource cmrDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
#Bean(name="oracleSessionFactory")
public LocalSessionFactoryBean crmSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(cmrDataSource());
sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
#Bean(name="oracleTransactionManager")
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(crmSessionFactory().getObject());
return transactionManager;
}
}
PostgresDatabaseConfig.java
package com.test.postgresql;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
public class PostgresDatabaseConfig {
#Value("${postgresql.db.driver}")
private String DB_DRIVER;
#Value("${postgresql.db.password}")
private String DB_PASSWORD;
#Value("${postgresql.db.url}")
private String DB_URL;
#Value("${postgresql.db.username}")
private String DB_USERNAME;
#Value("${postgresql.hibernate.dialect}")
private String HIBERNATE_DIALECT;
#Value("${postgresql.entitymanager.packagesToScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
#Bean(name="postgresqlDataSource")
#Primary
public DataSource cmrDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
#Bean(name="postgresqlSessionFactory")
public LocalSessionFactoryBean crmSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(cmrDataSource());
sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
#Bean(name="postgresqlTransactionManager")
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(crmSessionFactory().getObject());
return transactionManager;
}
}
Step 4: call to use:
in case mysql
package com.test.mysql.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Repository
#Transactional("mysqlTransactionManager")
public class TestMysqlDao {
#Autowired
#Qualifier("mysqlSessionFactory")
private SessionFactory sessionFactory;
}
In case oracle
package com.test.oracle.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Repository
#Transactional("oracleTransactionManager")
public class TestOracleDao {
#Autowired
#Qualifier("oracleSessionFactory")
private SessionFactory sessionFactory;
}
In case postgresql
package com.test.postgresql.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Repository
#Transactional("postgresqlTransactionManager")
public class TestPostgresDao {
#Autowired
#Qualifier("postgresqlSessionFactory")
private SessionFactory sessionFactory;
}
It's unclear what you mean by installing but if you want your application to start with different databases you can use different Spring profiles with your application.yml Spring boot profiles
---
spring:
profiles: postgres
datasource:
url:
username:
password:
driver-class-name: org.postgresql.Driver
---
spring:
profiles: mysql
datasource:
url:
username:
password:
driver-class-name: com.mysql.jdbc.Driver
You can then start the application with the respective profile
java -jar -Dspring.profiles.active=mysql yourapp.jar
You can define different connections and get them with specific methods
private DataSource mySqlDataSource;
private DataSource postgresDataSource;
public Connection getMySqlConnection() throws SQLException {
mySqlDataSource.getConnection();
}
public Connection getPostgresConnection() throws SQLException {
postgresDataSource.getConnection();
}
Related
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
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?
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.
I'm trying to get a small project of mine working, regarding the implementation of a process via WebServices.
Problem is: I dont even get to that point because I seem to hit trouble when booting Spring.
Spring is in fact booting but I cant get hibernate working ( atleast I think the problem lies with hibernate? ).
My ErrorLog: onPasteBin
My application.properties:
#New
spring.jpa.database-platform = org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql = true
# Hibernate
spring.jpa.hibernate.ddl-auto=create
#Old
# Thymeleaf
spring.thymeleaf.cache: false
# Database
db.driver: com.mysql.jdbc.Driver
db.url: jdbc:mysql://127.0.0.1:3306/igt
db.username: root
db.password: passwort
# Hibernate
hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql: true
hibernate.hbm2ddl.auto: create
entitymanager.packagesToScan: com.entities
And my DatabaseConfig.java:
package com.configs;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Value("${db.driver}")
private String DB_DRIVER;
#Value("${db.password}")
private String DB_PASSWORD;
#Value("${db.url}")
private String DB_URL;
#Value("${db.username}")
private String DB_USERNAME;
#Value("${hibernate.dialect}")
private String HIBERNATE_DIALECT;
#Value("${hibernate.show_sql}")
private String HIBERNATE_SHOW_SQL;
#Value("${hibernate.hbm2ddl.auto}")
private String HIBERNATE_HBM2DDL_AUTO;
#Value("${entitymanager.packagesToScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
hibernateProperties.put("hibernate.hbm2ddl.auto", HIBERNATE_HBM2DDL_AUTO);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager =
new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
}
I dont think the Application.java is really relevant to this, but here it is nonetheless:
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Maybe the Project Structure is helpful:
Screenshot of the ProjectStructure
Thanks very much in advance =)
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?