I want to use 2 or more jdbcTemplate in my project using application.properties.I try but got runtime exception.
########## My application.properties:-
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ccm_new
spring.datasource.username=test
spring.datasource.password=test
spring.oracledatasource.url=jdbc:oracle:thin:#localhost:1521:mastera
spring.oracledatasource.password=test
spring.oracledatasource.username=test
spring.oracledatasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#Bean(name = "dsMaster") ############
#Primary
#ConfigurationProperties(prefix="spring.oracledatasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "jdbcMaster") #############
public JdbcTemplate masterJdbcTemplate(#Qualifier("dsMaster") DataSource dsMaster)
{
return new JdbcTemplate(dsMaster);
}
################I use the mysql connection normally but on use of oracle connection i got
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Cannot create JDBC driver of class '' for connect URL 'null'
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:81)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:371)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:446)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:456)
at enter code here
I got it where i am wrong,I want to make mysql connection through application.properties without #bean configuration.If you want to take 2 or more connection you just need to define all the datasource with their #ConfigurationProperties(prefix="spring.mysqldatasource") different prifix other than "spring.datasource".prifix " spring.datasource" use only when we need to make connection from only one database.Here is the final working code example:-
application.properties
spring.mysqldatasource.driver-class-name=com.mysql.jdbc.Driver
spring.mysqldatasource.url=jdbc:mysql://localhost:3306/ccm_new
spring.mysqldatasource.username=test
spring.mysqldatasource.password=test
spring.mysqldatasource.dbcp2.initial-size=5
spring.mysqldatasource.dbcp2.max-total=15
spring.mysqldatasource.dbcp2.pool-prepared-statements=true
spring.oracledatasource.url=jdbc:oracle:thin:#localhost:1521:mastera
spring.oracledatasource.password=test
spring.oracledatasource.username=test
spring.oracledatasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.oracledatasource.dbcp2.initial-size=5
spring.oracledatasource.dbcp2.max-total=15
spring.oracledatasource.dbcp2.pool-prepared-statements=true
#Configuration
public class PrototypeUtility {
#Bean(name = "dsMaster")
#Primary
#ConfigurationProperties(prefix="spring.oracledatasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "jdbcMaster")
public JdbcTemplate masterJdbcTemplate(#Qualifier("dsMaster") DataSource dsMaster) {
return new JdbcTemplate(dsMaster);
}
#Bean(name = "dsMasterMysql")
#ConfigurationProperties(prefix="spring.mysqldatasource")
public DataSource primaryDataSourceMysql() {
return DataSourceBuilder.create().build();
}
#Bean(name = "jdbcMasterMysql")
public JdbcTemplate masterMysqlJdbcTemplate(#Qualifier("dsMasterMysql") DataSource dsMasterMysql) {
return new JdbcTemplate(dsMasterMysql);
}
}
and then i autowired the both connection :-
#Autowired
private JdbcTemplate jdbcMasterMysql;
#Autowired
public JdbcTemplate jdbcMaster;
This code run successfully for me .
If any one have doubt,Don't hesitate to ask.
I got it where i am wrong,I want to make mysql connection through application.properties without #bean configuration.If you want to take 2 or more connection you just need to define all the datasource with their #ConfigurationProperties(prefix="spring.mysqldatasource") different prifix other than "spring.datasource".prifix " spring.datasource" use only when we need to make connection from only one database.Here is the final working code example:-
application.properties
spring.mysqldatasource.driver-class-name=com.mysql.jdbc.Driver
spring.mysqldatasource.url=jdbc:mysql://localhost:3306/ccm_new
spring.mysqldatasource.username=test
spring.mysqldatasource.password=test
spring.mysqldatasource.dbcp2.initial-size=5
spring.mysqldatasource.dbcp2.max-total=15
spring.mysqldatasource.dbcp2.pool-prepared-statements=true
spring.oracledatasource.url=jdbc:oracle:thin:#localhost:1521:mastera
spring.oracledatasource.password=test
spring.oracledatasource.username=test
spring.oracledatasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.oracledatasource.dbcp2.initial-size=5
spring.oracledatasource.dbcp2.max-total=15
spring.oracledatasource.dbcp2.pool-prepared-statements=true
#Configuration
public class PrototypeUtility {
#Bean(name = "dsMaster")
#Primary
#ConfigurationProperties(prefix="spring.oracledatasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "jdbcMaster")
public JdbcTemplate masterJdbcTemplate(#Qualifier("dsMaster") DataSource dsMaster) {
return new JdbcTemplate(dsMaster);
}
#Bean(name = "dsMasterMysql")
#ConfigurationProperties(prefix="spring.mysqldatasource")
public DataSource primaryDataSourceMysql() {
return DataSourceBuilder.create().build();
}
#Bean(name = "jdbcMasterMysql")
public JdbcTemplate masterMysqlJdbcTemplate(#Qualifier("dsMasterMysql") DataSource dsMasterMysql) {
return new JdbcTemplate(dsMasterMysql);
}
}
Related
Here is the application.properties of my Spring Boot 2.5 :
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME}
spring.datasource.username=${MYSQL_USER:root}
spring.datasource.password=${MYSQL_PASSWORD:root}
I migrated my application from Spring MVC 4.3 and I don't use JPA on the latest version of Spring Boot.
So I configured a #Beandatasource like this:
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getRequiredProperty("spring.datasource.url"));
dataSource.setUsername(env.getRequiredProperty("spring.datasource.username"));
dataSource.setPassword(env.getRequiredProperty("spring.datasource.password"));
return dataSource;
}
However, this does not work because instead of having the value of the environment variable, I have the name of the environment variable, i.e. ${MYSQL_USER:root} for example.
My question is what is Spring's recommended way here to set up environment variables much like Laravel's .env in my datasource() and also in the application.properties if I decide to use JPA later on?
The reason and the important point: I don't want to push my credentials on git
EDIT :
HibernateUtil :
static {
try {
Properties applicationProps = new Properties();
File file = ResourceUtils.getFile("classpath:application.properties");
InputStream input = new FileInputStream(file);
applicationProps.load(input);
Properties properties = new ApplicationConf().hibernateProperties();
// Configure datasource
properties.setProperty("hibernate.connection.driver_class", applicationProps.getProperty("spring.datasource.driver-class-name"));
properties.setProperty("hibernate.connection.url", applicationProps.getProperty("spring.datasource.url"));
properties.setProperty("hibernate.connection.username", applicationProps.getProperty("spring.datasource.username"));
properties.setProperty("hibernate.connection.password", applicationProps.getProperty("spring.datasource.password"));
properties.setProperty("hibernate.current_session_context_class", "thread");
properties.setProperty("hibernate.jdbc.batch_size", Integer.toString(BATCH_SIZE));
// Override some properties
properties.setProperty("hibernate.format_sql", "false");
properties.setProperty("hibernate.show_sql", "false");
} catch {}
...
}
Best regards,
You can use the #Value annotation to pull the properties and also their defaults.
#Value("${spring.datasource.username}")
private String userName;
#Bean
public DataSource dataSource() {
...
dataSource.setUsername(userName);
...
return dataSource;
}
You can also omit the default from the application.properties file and specify a default value for the property using Value annotation -
#Value("${spring.datasource.username:root}")
private String userName;
#Bean
public DataSource dataSource() {
...
dataSource.setUsername(userName);
...
return dataSource;
}
Or can even be injected in the method-
#Bean
public DataSource dataSource(#Value("${spring.datasource.username:root}") String userName) {
...
dataSource.setUsername(userName);
...
return dataSource;
}
I was trying to insert data into database in my cucumber tests module in spring-boot application.
When start spring app with test profile (mvn spring-boot:run -Dspring-boot.run.profiles=test) it start up the application and run properly. The issue is during cucumber test execution when try to setup the datasource (as pointed out ** line in the code below) it comes as null. So should I setup the datasource again? If so how.
It's not cucumber test related issue, The issue is I can't access the datasource which have set in the main app.
Below is the code
#ContextConfiguration(classes = MainApp.class, loader = SpringBootContextLoader.class)
#ActiveProfiles("test")
#Configuration
#PropertySource({"classpath:create-sql.xml"})
public class TestHelper {
#Value("${CreateSql}")
private String CreateSql;
#Autowired
private SqlQueryBuilder sqlQueryBuilder;
#Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
private UserPreferenceFormatter formatter;
#Autowired
private DataSource dataSource;
public static void getDataList() throws IOException {
MapSqlParameterSource sqlParamSource = new MapSqlParameterSource();
sqlQueryBuilder = new SqlQueryBuilder();
jdbcTemplate = new NamedParameterJdbcTemplate(dataSource); ****
String parsedSql = sqlQueryBuilder.parseSql(CreateSql,null,null,null);
List<DataSummary> dataSummaries = jdbcTemplate.query(parsedSql, sqlParamSource, new DataSummaryRowMapper(null,formatter));
}
application-test.yml file under resources folder with all spring datasources within test module
app-db-url: jdbc:oracle:....
app-db-user: USERNAME
spring:
datasource:
password: PWD
I went through below solution as well
Solution-1
Solution-2
Deployment module app-config.yml
....
data:
# Database
app-db-url : ##app-db-url##
app-db-user: ##app-db-user##
......
It looks like you are missing code that defines that DataSource bean.
You should have something like this:
#Configuration
public class DataSourceConfig {
#Bean
public DataSource getDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.h2.Driver");
dataSourceBuilder.url("jdbc:h2:mem:test");
dataSourceBuilder.username("SA");
dataSourceBuilder.password("");
return dataSourceBuilder.build();
}
}
or something like that:
#Bean
public DataSource getDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.username("SA");
dataSourceBuilder.password("");
return dataSourceBuilder.build();
}
and the rest of the propertied can go into a property file.
Starting from a program that was connected to a mysql database, using spring, JPA and JDBC, I am trying to configure that application to use the H2 database in embedded mode.
With MYSQL everything works fine, but with H2 not.
I can not get H2 to return any records, although the records are there so if I do the same query through JDBC, if I see them.
The configuration that I have is the following:
#Configuration
#EnableJpaRepositories("yages.yagesserver")
#EnableTransactionManagement
public class JpaConfig {
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder
.setType(EmbeddedDatabaseType.H2)
.setName("yagesh2")
.ignoreFailedDrops(true)
.addScript("db/sql/create-db.sql")
.addScript("db/sql/insert-data.sql")
.generateUniqueName(false)
.build();
return db;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) throws NamingException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[]{"yages.yagesserver", "yages.yagesserver.dao"});
em.setPersistenceUnitName("yages-server");
em.setJpaVendorAdapter(jpaVendorAdapter());
em.afterPropertiesSet();
return em;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(false);
jpaVendorAdapter.setDatabase(Database.H2);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
So if I write this code:
String s="SELECT cal_ano,cal_mes,cal_fecini,cal_fecfin from calendario where cal_ano=? and cal_mes = ?";
List<Calendario> cal =
jdbc.query(s, new Object[] { ano,mes},
(rs, rowNum) -> new Calendario(
rs.getInt("cal_ano"),rs.getInt("cal_mes"),rs.getDate("cal_fecini"),rs.getDate("cal_fecfin"))
);
System.out.println("getDatosSemana. Size "+cal.size()+ "Fecha Inicio: "+cal.get(0).getFechaInicio());
Optional<Calendario> calOpc = calendarioRepositorio.getCalendario(new CalendarioKey(ano - 1, mes));
System.out.println("getDatosSemana. Optional is present: "+calOpc.isPresent());
When I use JDBC I see that in the calendar table if the record exists, but when using JPA, it does not seem to find anything.
This is the output in my console:
getDatosSemana. Size 1Fecha Inicio: 2018-01-28
Hibernate: select calendario0_.cal_ano as cal_ano1_0_0_, calendario0_.cal_mes as cal_mes2_0_0_, calendario0_.cal_fecfin as cal_fecf3_0_0_, calendario0_.cal_fecini as cal_feci4_0_0_ from calendario calendario0_ where calendario0_.cal_ano=? and calendario0_.cal_mes=?
getDatosSemana. Optional is present: false
Of course I have the DAO classes and my repository that extends from a CrudRepository.
Any suggestions, please?
I'm sorry. I have found the error.
It was a failure foolishness. I called the JPA function with the parameters of year and month reversed.
Sometimes you do not see the obvious.
I want to use HikariCP as JDBC connection pool in my Spring boot application. I have two datasources (MySQL database as the primary database and accessing those data through Hibernate and additionally an Oracle database for reading some other data through JDBCTemplate).
I set the MySQL datasource as primary bean:
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSourceProperties mySQLDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSource mySQLDataSource() {
return mySQLDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("oracle.datasource")
public DataSourceProperties oracleDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "oracleDatabase")
#ConfigurationProperties("oracle.datasource")
public DataSource oracleDataSource() {
return oracleDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
public JdbcTemplate oracleJdbcTemplate(#Qualifier("oracleDatabase") DataSource oracleDb) {
return new JdbcTemplate(oracleDb);
}
and I put the following configurations in my application.properties :
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=7
spring.datasource.hikari.pool-name=Test-1
spring.datasource.hikari.data-source-properties.prepStmtCacheSize=250
spring.datasource.hikari.data-source-properties.prepStmtCacheSqlLimit=2048
spring.datasource.hikari.data-source-properties.cachePrepStmts=true
spring.datasource.hikari.data-source-properties.useServerPrepStmts=true
Unforuntately, these HikariCP configurations are not being read :
HikariConfig - dataSourceJNDI..................none
HikariConfig - dataSourceProperties............{password=<masked>}
HikariConfig - driverClassName................."com.mysql.jdbc.Driver"
HikariConfig - healthCheckProperties...........{}
HikariConfig - healthCheckRegistry.............none
HikariConfig - idleTimeout.....................600000
HikariConfig - initializationFailFast..........true
HikariConfig - initializationFailTimeout.......1
HikariConfig - isolateInternalQueries..........false
HikariConfig - jdbc4ConnectionTest.............false
HikariConfig - jdbcUrl........................."jdbc:mysql://localhost:3306/testDB"
HikariConfig - leakDetectionThreshold..........0
HikariConfig - maxLifetime.....................1800000
HikariConfig - maximumPoolSize.................10
HikariConfig - metricRegistry..................none
HikariConfig - metricsTrackerFactory...........none
HikariConfig - minimumIdle.....................10
HikariConfig - password........................<masked>
HikariConfig - poolName........................"HikariPool-1"
Creating the HikariCP beans and deactivating the DataSource autoconfiguration and removing "spring.datasource" :
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
#SpringBootApplication
#ComponentScan
public class SpringApplication {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariConfig hikariConfig() {
return new HikariConfig();
}
#Bean
public DataSource dataSource() {
return new HikariDataSource(hikariConfig());
}
solves my problem :
HikariConfig - dataSourceJNDI..................none
HikariConfig - dataSourceProperties............{password=<masked>, prepStmtCacheSqlLimit=2048, cachePrepStmts=true, useServerPrepStmts=true, prepStmtCacheSize=250}
HikariConfig - driverClassName................."com.mysql.jdbc.Driver"
HikariConfig - healthCheckProperties...........{}
HikariConfig - healthCheckRegistry.............none
HikariConfig - idleTimeout.....................600000
HikariConfig - initializationFailFast..........true
HikariConfig - initializationFailTimeout.......1
HikariConfig - isolateInternalQueries..........false
HikariConfig - jdbc4ConnectionTest.............false
HikariConfig - jdbcUrl........................."jdbc:mysql://localhost:3306/testDB?autoReconnect=true"
HikariConfig - leakDetectionThreshold..........0
HikariConfig - maxLifetime.....................1800000
HikariConfig - poolName........................"Test-1"
But then the Flyway showing some weird warnings which were not shown before and I have to create the database Schema manually before running the Spring application, that is : the create schema does not work anymore.
[WARN ] JdbcTemplate - DB: Can't create database 'test'; database exists (SQL State: HY000 - Error Code: 1007)
[WARN ] JdbcTemplate - DB: Unknown table 'testSchema.tenant' (SQL State: 42S02 - Error Code: 1051)
[WARN ] JdbcTemplate - DB: Unknown table 'testSchema.user' (SQL State: 42S02 - Error Code: 1051)
My Flyway SQL scripts are plain DDL scripts :
CREATE SCHEMA IF NOT EXISTS `testSchema` DEFAULT CHARACTER SET utf8 ;
DROP TABLE IF EXISTS `testSchema`.`tenant`;
CREATE TABLE `testSchema`.`tenant` (
`id` int NOT NULL AUTO_INCREMENT,
I think that disabling the Auto-Datasource configuration is not the best solution since Flyway stops creating the schema and showing warnings. Is there any other way to solve this ?
Declaring your own DataSource will already have implicity disabled Spring Boot's auto-configuration of a data source. In other words this won't be having any effect:
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
I think the problem lies in the fact that you aren't binding Hikari-specific configuration to your MySQL DataSource. You need to do something like this:
#Bean
#Primary
#ConfigurationProperties("spring.datasource.hikari")
public DataSource mySQLDataSource() {
return mySQLDataSourceProperties().initializeDataSourceBuilder().build();
}
This will mean that your mySQLDataSourceProperties are configured with general-purpose data source configuration. They then create a HikariDataSource which is further configured with the Hikari-specific configuration.
Thank you Andy for your fast and valuable answer ! You set me on the right track. After fiddling around, I found this configuration is working for me :
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
//#ConfigurationProperties("spring.datasource.hikari") can also be used, no difference
public DataSourceProperties mySQLDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties("spring.datasource.hikari")
public DataSource mySQLDataSource() {
return mySQLDataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariConfig hikariConfig() {
return new HikariConfig();
}
#Bean
public DataSource dataSource() {
return new HikariDataSource(hikariConfig());
}
and I had to add these settings in the application.properties:
# this is absolutely mandatory otherwise BeanInstantiationException in mySQLDataSource !
spring.datasource.url=${JDBC_CONNECTION_STRING}
spring.datasource.hikari.jdbc-url=${JDBC_CONNECTION_STRING}
spring.datasource.hikari.username=user
spring.datasource.hikari.password=pass
I used the following approach
first.datasource.jdbc-url=jdbc-url
first.datasource.username=username
first.datasource.password=password
.
.
.
.
=================== In Java Configuration File ==================
#Primary
#Bean(name = "firstDataSource")
#ConfigurationProperties(prefix = "first.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "firstEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("firstDataSource") DataSource dataSource) {
Map<String, String> props = new HashMap<String, String>();
props.put("spring.jpa.database-platform", "org.hibernate.dialect.Oracle12cDialect");
.
.
.
return builder.dataSource(dataSource).packages("com.first.entity").persistenceUnit("firstDB")
.properties(props)
.build();
}
#Primary
#Bean(name = "firstTransactionManager")
public PlatformTransactionManager firstTransactionManager(
#Qualifier("firstEntityManagerFactory") EntityManagerFactory firstEntityManagerFactory) {
return new JpaTransactionManager(firstEntityManagerFactory);
}
second.datasource.jdbc-url=jdbc-url
second.datasource.username=username
second.datasource.password=password
.
.
.
.
=================== In Java Configuration File ==================
#Bean(name = "secondDataSource")
#ConfigurationProperties(prefix = "second.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "secondEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("secondDataSource") DataSource dataSource) {
Map<String, String> props = new HashMap<String, String>();
props.put("spring.jpa.database-platform", "org.hibernate.dialect.Oracle12cDialect");
.
.
.
return builder.dataSource(dataSource).packages("com.second.entity").persistenceUnit("secondDB")
.properties(props)
.build();
}
#Bean(name = "secondTransactionManager")
public PlatformTransactionManager secondTransactionManager(
#Qualifier("secondEntityManagerFactory") EntityManagerFactory secondEntityManagerFactory) {
return new JpaTransactionManager(secondEntityManagerFactory);
}
I am trying to develop tests for my application (I found out about the tests very late...) and I am stuck and the basic configuration. I have googled through many examples and none of them satisfied me and frankly left me a bit confused.
What I am trying to achieve is to load an import.sql on start of the test (which is a dump file from existing MySQL schema) and load it into H2 database.
Here is the hibernate config file:
#Configuration
#EnableTransactionManagement
#ComponentScan({ "kamienica.feature" })
public class HibernateTestConfiguration {
#Autowired
ApplicationContext applicationContext;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "kamienica" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;"
+ "INIT=CREATE SCHEMA IF NOT EXISTS kamienica;DB_CLOSE_ON_EXIT=FALSE");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
properties.put("hibernate.hbm2ddl.auto", "update");
// this is where I tried to load script the first time:
// properties.put("hibernate.hbm2ddl.import_files", "kamienica.sql");
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
Everytime I start a test I get a message that:
org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata INFO:
HHH000262: Table not found: apartment
And I get empty/null values when trying to retrieve anything
I have tried to load sql file in the hibernate config (via hibernate properties) as well as in superclass which all my test classes are planned to extend:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { HibernateTestConfiguration.class })
public class BaseTest {
private EmbeddedDatabase db;
#Autowired
private SessionFactory sessionFactory;
//second attempt to load sql file
#Before
public void setUp() throws Exception {
db = new EmbeddedDatabaseBuilder().addScript("import.sql").build();
}
#After
public void tearDown() throws Exception {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
How can I load sql file and prepare the H2 database to perform the tests?
I hope this spring boot approach will help you. First create a resources directory (classpath for springboot)in the src/test directory at the root of your project.
In this directory, you will start placing your fixture SQL data files named say data.sql .
Then, create a application.properties file on the same level (same directory see screenshot). This file should be populated as shown here:
spring.datasource.url = jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
#spring.datasource.url: jdbc:mysql://localhost:3306/yourDB
#spring.datasource.username = root
#spring.datasource.password =
# Hibernate
hibernate.show_sql: true
#hibernate.dialect: org.hibernate.dialect.MySQL5Dialec
spring.jpa.hibernate.ddl-auto=none
Screenshot:
Now your tester method.
#RunWith(SpringJUnit4ClassRunner.class)
....
#Autowired
private DataSource ds; //your application.properties
#Autowired
private WebApplicationContext context;
private static boolean loadDataFixtures = true;
private MockMvc mockMvc;
....
#Before
public void setupMockMvc() {
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
#Before
public void loadDataFixtures() {
if (loadDataFixtures) {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(context.getResource("classpath:/data.sql"));
DatabasePopulatorUtils.execute(populator, ds);
loadDataFixtures = false;
}
}
#Test
public void yourmethod() {
assertEquals(3, repository.count()); //example
}
Without any output or the complete stacktrace, the only I can suggest you is:
You aren't showing any #Test method. How are you getting that error?
Is your file import.sql in src/test/resources folder? (note the test path)
Is your sql script well formated? Have you tried to run once exported? Could you post the part of the sql script wich creates the apartment table ?
If all are true, maybe the problem is not about loading the sql but how it's used, or the content of the script, or the name of the tables, etc...
After a long 'investigation' I have concluded that the problem was hidden somewhere in he DBUnit, TestNG setup.
I decided to keep it simple and switched to JUnit tests.
In case others might have similar problems here is the config file that works for me:
#Configuration
#EnableTransactionManagement
#ComponentScan({ "kamienica.feature" })
public class JUnitConfig {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "kamienica" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:kamienica;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
properties.put("hibernate.hbm2ddl.auto", "create");
return properties;
}
#Bean
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
All is needed now is to insert import.sql file in the resources folder.
I also found out that each insert statements must be in one line no matter how long it is, otherwise it won't be loaded.
Finally a simple test class:
#ContextConfiguration(classes = { JUnitConfig.class })
#RunWith(SpringJUnit4ClassRunner.class)
public class ApartmentServiceTest extends AbstractServiceTest{
#Autowired
ApartmentService service;
#Test
public void getList() {
List<Apartment> list = service.getList();
System.out.println(list.toString());
assertEquals(5, list.size());
}
}