Spring Boot with multiple datasources and in memory database - spring

I'm trying to set up Spring Boot to work with multiple datasources. I have followed the instructions for setting up two datasources and set one of them primary.
#Configuration
#EnableJpaRepositories(basePackages={"my.postgres.repositories"}
entityManagerFactoryRef="postgresEntitymanager"
transactionManagerRef="postgresTransactionManager")
public class PgConfig {
#Primary
#Bean(name="postgresDS")
#ConfigurationProperties(prefix="spring.datasource.postgres")
public DataSource postgresDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name="postgresEntityManager")
public LocalContainerEntityManagerFactoryBean postgresEntityManager(EntityManagerFactoryBuilder builder) {
return builder.dataSource(postgresDataSource())
.packages("my.postgres.domain")
.persistenceUnit("postgresPersistenceUnit")
.build();
}
#Primary
#Bean(name = "postgresTransactionManager")
public PlatformTransactionManager postgresTransactionManager(
#Qualifier("postgresEntityManager") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
I have a second configuration class for oracle which lacks the #Primary annotation but is very similar. I have also added this to my main class to exclude datasource auto configuration.
#SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
The problem that I'm facing is this setup doesn't allow my Integration tests that are supposed to run against an H2 databse to open a connection...
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException: Could not open connection
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException: Could not open connection
Caused by: org.hibernate.exception.JDBCConnectionException: Could not open connection
Caused by: java.sql.SQLException: The url cannot be null
I'm using a separate application.properties file under src/integrationtest/resources which contains
spring.jpa.database=H2
How do I get my integration tests to use H2 for the repositories that I'm using when running my tests?
If I don't include my custom datasources everything seems to work fine.
Thanks

You can add your own test's configuration with h2 database but use other database in production. You've excluded DataSourceAutoConfiguration in your spring application class, but it's usefull in your integration tests.
One simple solution is using a different spring application class only for your integrating tests without excluding DataSourceAutoConfiguration or just implement your own DataSourceAutoConfiguration and enable it. You can decide when will your own DataSourceAutoConfiguration be enabled or not within your own implementation. For example, if there are junit or spring-test exists in your classpath it will be enabled, otherwise will be disabled. This requires the junit or spring-test not going to be included in production, which can be handled by dependencies management such as maven.

Related

Can't deploy Spring Boot (v2.6.6) project to Weblogic (v12.2.1.3) , due to javax.naming.NameNotFoundException

I'm trying to deploy a Spring boot application to weblogic, and connect the app to a Gridlink datasource using this method in #configuration to get the data source.
#Bean(name = "dataSourceA",destroyMethod = "")
public DataSource dataSourceA() throws NamingException {
JndiTemplate jndiTemplate = new JndiTemplate();
InitialContext ctx = (InitialContext) jndiTemplate.getContext();
return (DataSource) ctx.lookup(env.getProperty("DatabaseAGridLink"));
}
On Weblogic, the JNDI name for the data source is "DatabaseAGridLink", which I am hardcoding in the creation of the bean.
However, when I compile my project into a .war file and host on Weblogic- it runs into an error when searching for the data source:
javax.naming.NameNotFoundException: Unable to resolve 'DatabaseAGridLink'. Resolved ''; remaining
name 'DatabaseAGridLink'
If I restart my Weblogic, it no longer errors and the Spring Boot application can connect to the datasource on Weblogic, run db queries- functioning without issues. Problem is, this isn't a real solution- as any time the project is updated the Weblogic needs to be restarted and there are other applications running which makes this impossible irrespective of being a bad solution in the first place.
Thinking it's an issue with how the datasource is initialized in Spring boot, I have tried other methods of connection such as:
#Bean
public DataSource dataSourceA() throws Exception{
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("DatabaseAGridLink");
}
Or different ways of specifying the JNDI name on both data source initialization beans:
ctx.lookup(env.getProperty("java:jdbc/DatabaseAGridLink"));
ctx.lookup(env.getProperty("jdbc/DatabaseAGridLink"));
ctx.lookup(env.getProperty("java:comp/jdbc/DatabaseAGridLink"));
dataSourceLookup.getDataSource("java:jdbc/DatabaseAGridLink");
etc..
These changes has had no effect, other than the name no longer being found as none of these other naming schemes are valid.
What could be causing this failure of datasource connection between Spring Boot and a Weblogic instance? (Especially considering that it succeeds after weblogic is restarted, which seems to imply that the Spring boot app is indeed looking for the correct JNDI name with it's bean and this isn't a naming problem)

Spring Boot and Spring Session: How to control the DataSource

I'm experimenting with Spring Boot and Spring session together, specifically using JDBC.
Just adding the line in application.properties:
spring.session.store-type=jdbc
made it just work, which is nice because I happen to also have some data source properties in that file, ie
myapp.datasource.url=jdbc:mysql://localhost/etc...
myapp.datasource.driver-class-name=com.mysql.jdbc.Driver
But I'm actually using those for my own data source with my own configuration, like so:
#Configuration
#PropertySource("classpath:credentials.properties")
public class DataSourceConfig {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "myapp.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
and as far as I can tell, Spring Session is creating its own data source instead of using mine. Is there a way I can get it to use mine instead?
(my real data source has some additional configs with Hikari not shown here)
Spring Session itself does not create DataSource but rather uses the one present in your application context, if it's the either:
the only DataSource bean
DataSource marked as #Primary
Also if you wish to use a specific DataSource for Spring Session (for example, if you have multiple DataSources in your application) you can do that by:
annotating DataSource marked as designated for Spring Session by #SpringSessionDataSource (Spring Session 2.0 onwards)
providing JdbcTemplate bean that uses the desired DataSource and naming it springSessionJdbcOperations (Spring Session 1.x)
The Spring Session JDBC configuration capabilities and logic should be quite easy to understand from the JdbcHttpSessionConfiguration.

Spring/tomcat Cannot load driver class: com.mysql.jdbc.driver

Lately I have been trying to learn spring boot. I have the following relevant files:
an #Configuration class: I use this to generate the entitymanagerfactory
an #Entity class: I use this to map to a mysql table instance
an #Repository crudrepository interface: this is built in to spring
an #Controller class: this is used to test auto-wiring (when I can inject, I will move this to the service layer)
an #SpringBootApplication class: this runs my application
an application.properties file
a pom.xml: this is used for maven and includes mysql jar
an entity class mapped to a mysql table and a UserRepository class(annotated with #Repository). I am trying to inject the crudrepository class via #Autowire annotation, but spring is having difficulty creating the datasource for it because it cannot find the mysql driver. What confuses me is that I have the mysql dependency in maven and I am deploying this on a glassfish 4 server, but Spring is trying to use apache tomcat to connect to the database. Below is my stack trace, code snippets, and mysql-connector:
Relevant Stack Trace (inner exception)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: Cannot load driver class: com.mysql.jdbc.driver
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 62 common frames omitted
Caused by: java.lang.IllegalStateException: Cannot load driver class: com.mysql.jdbc.driver
notice how this is trying to use org.apache.tomcat to create datasource, even though I am using a glassfish server. Does this matter?
Source Code: the first relevant exception occurs when spring tries to inject the datasource bean that is a parameter to this method and can't create it
#Configuration
#EnableAutoConfiguration
public class AppConfigUtil {
#Autowired
#Bean
public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
bean.setPackagesToScan("com.connor");
bean.setDataSource(dataSource);
return bean.getObject();
}
Maven (pom.xml) for mysql jar:
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
application.properties: this is the entirety of my application.properties file spring uses to generate datasource
spring.datasource.url=jdbc:mysql://localhost:3307/craigslist
spring.datasource.username=dbadmin
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.driver
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=true
Here is picture of my maven dependencies: the mysql jar is present:
downloaded maven dependencies: including mysql jar
Any ideas on how to fix this?
Assuming you are using Spring boot.
Here are some things you can do to make it work (You might have done some of these, I added anything I can think of just to make sure):
Remove your AppConfigUtil class because Spring boot will "magically" find the datasource for you if your application.properties is configured right.
Add #SpringBootApplication to your ConnerApplication.java class
Add spring-boot-starter-data-jpa dependency in your pom
Some side notes:
#Autowire is not intended to be marked with #Bean annotation. #Autowire CAN be used to autowire bean which is annotated with #Bean.
EDIT :
I realized that OP wants to deploy it on Glassfish. In that case, you will need to tweak Spring to produce a deployable war file and configure your application container (glassfish) to include a jdbc driver. All of it is doable but requires a lot of efforts.
I suggested that you go with embedded tomcat approach if you use Spring-boot for new project. It is basically battle-ready. You can hardly go wrong with this.
You don't need declare in pom.xml
spring.datasource.driver-class-name=com.mysql.jdbc.driver
You can read my configuration in a simple app using Spring Boot here
Beside, if you're using Spring Boot you don't need use codes "Source Code: the first relevant exception occurs when spring tries to inject the datasource bean that is a parameter to this method and can't create it..."

Initialize standalone databases, Spring Boot and MyBatis

I'm building Spring Boot + MyBatis project using standalone postgresql database.
Well, for some reason, "convention-based" database initialization doesn't occur. I added data source manually, created sql-scripts, but when I run the project, from the log it's not even processing these scripts. I want to understand how the process works for not-embedded databases.
Can one create an instance of data source using code?
Should I link data source in property file or separate class?
What one should do to link separate data source (postgresql in this case) with Spring Boot configuration?
Yes
#Bean
public DataSource dataSource() {
DataSourceBuilder.create()
.url("jdbc:postgresql://localhost:5432/database")
.username("username")
.password("password")
...
.build();
}
2-3. You can use property file along with providing java based DataSourceConfiguration
spring.datasource.url: jdbc:postgresql://localhost:5432/database
spring.datasource.username: username
spring.datasource.password: pasword
And refers these properties in your Configuration class as follows:
#Bean
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
If you have only one database to connect to, the most convenient way is to add it's connection properties into property file, prefixed with spring.datasource (scroll here to check available options) and add org.postgresql dependency to pom.xml (build.grade) file and SpringBoot will do the rest.

How do you use a Tomcat JNDI JDBC datasource in Spring Boot

I have a Spring boot application and want to deploy as a WAR to Tomcat 7. As part of this I need to keep configuration out of the WAR, so that I can deploy the same war to my stage and production servers and have it pickup the mysql connection via configuration.
To this end I want to configure my Spring Boot app to use a mysql connection configured as a JNDI datasource in the Tomcat instance.
Can spring boot do this and if so how?
Alternatively is this easy to do in Spring 4 without resorting to xml based configuration.
If you're using Spring Boot 1.2 or greater, this got easier. You can just add this to application.properties
spring.datasource.jndi-name=java:comp/env/jdbc/my_database
The relevant docs: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connecting-to-a-jndi-datasource
#Bean
public DataSource dataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource("jdbc/apolloJNDI");
return dataSource;
}
No "java:comp/env/" its needed because JndiDataSourceLookup internaly calls convertJndiName that add this part. In other clases you should set the complete path.
Here's what I had done.
Add the following to to Application.java
#Bean
public DataSource dataSource() {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/mysqldb");
return dataSource;
}
Then follow the example in https://spring.io/guides/gs/accessing-data-jpa/ to set up the TransactionManager and Hibernate specific properties.
A hint for all of you using Spring Boot with an external Tomcat. Please ensure your war doesn't contain any tomcat jars. Multiple versions of same jar will produce hidden ClassCastException manifested by javax.naming.NamingException.

Resources