How to connect to PostgreSQL in Spring Boot 2 using a Bean - spring-boot

I would like to connect to PostgreSQL using a bean (#Bean) and Spring Data.
At this bean, I would like to use my own customer properties in application.properties file, like these properties below
my.db.user=postgres
my.db.password=root
my.db.url=jdbc:postgresql://localhost:5432/mydb
I can't use use default properties (spring.datasource.url , spring.datasource.username, etc .. )

Spring Boot 2 by default uses Hikari to manager connections.
So, you can do it.
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
#Configuration
public class DatabaseConfig {
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public HikariDataSource dataSource() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.build();
}
}
application.properties
spring.datasource.platform=postgres
spring.datasource.jdbc-url=jdbc:postgresql://localhost:5432/dbname
spring.datasource.username=postgres
spring.datasource.password=123456
If you wanna use tomcat-jdbc, add the following config.
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
Reference link : https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0.0-M2-Release-Notes#default-connection-pool

You can create your own DataSource with your custom database properties the following way.
#Bean
#ConfigurationProperties(prefix="my.db")
public DataSource myDataSource() {
return DataSourceBuilder.create().build();
}
Have a look at the following description to configure two databases for a full example, this explains how you can use your own properties
two databases example

Related

How can I configure multiple databases with springboot one being JPA and the other 5 plain jdbc?

For a project with a springboot backend, I have to use 1 database in Postgresql to save information and to add a history feature to the application and 5 other databases in Oracle on which I only have readonly access on views. For those 5 I only have to get ponctual values and the databases are huge so it doesn't make sense to have repositories and entities. But I can't find any information on how to configure multiple databases if one uses ORM and the others don't.
application.properties
#informations for the history database
spring.datasource.url = jdbc:postgresql://localhost:5432/NA_db
spring.datasource.username = userNA
spring.datasource.password = userNApwd
spring.datasource.driver-class-name=org.postgresql.Driver
spring.session.jdbc.initialize-schema: always
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
DataSourceConfiguration.java
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.zaxxer.hikari.HikariDataSource;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "historyEntityManagerFactory", transactionManagerRef = "historyTransactionManager", basePackages = "mypackage.history.dao")
#EntityScan("mypackage.history.model.entities")
public class DataSourceConfig {
#Primary
#Bean
#ConfigurationProperties("spring.datasource")
public DataSourceProperties SourceProperties() {
return new DataSourceProperties();
}
#Primary
#Bean(name = "historyDatasource")
#ConfigurationProperties(prefix = "spring.datasource.configuration")
public DataSource dataSource() {
return SourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
#Primary
#Bean(name = "historyEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("historyDatasource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("mypackage.history.model.entities")
.persistenceUnit("historyPU").build();
}
#Primary
#Bean(name = "historyTransactionManager")
public PlatformTransactionManager barTransactionManager(
#Qualifier("historyEntityManagerFactory") EntityManagerFactory barEntityManagerFactory) {
return new JpaTransactionManager(barEntityManagerFactory);
}
}
Connection and Statement creation for the other databases
Class.forName("oracle.jdbc.OracleDriver");
connectionYG = DriverManager.getConnection(urlYG, user, password);
stmtYG = connectionYG.createStatement();
connectionZA = DriverManager.getConnection(urlZA, user, password);
stmtZA = connectionZA.createStatement();
connectionZB = DriverManager.getConnection(urlZB, user, password);
stmtZB = connectionZB.createStatement();
connectionZC = DriverManager.getConnection(urlZC, user, password);
stmtZC = connectionZC.createStatement();
connectionZD = DriverManager.getConnection(urlZD, user, password);
stmtZD = connectionZD.createStatement();
Here is what I tried with a configuration class for the history database and instantiation of the connections directly where I need them in my service class.
Here is what I get :
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
I am pretty sure I just don't configurate my databases the correct way but I can't find the correct informations. Have you any ideas on how am I supposed to do ?

Ehcache - Cannot find cache name for Builder

I've looked through a lot of similar questions asked here but I'm still not able to find a solution so here's my issue:
I'm trying to setup Ehcache on springboot.
Spring 2.2.6.RELEASE
Ehcache 3.8.1
CacheService
I've got a cache named `myCache`.
#Cacheable(value = "myCache")
#GetMapping("/get")
public String get();
CacheConfig
And my config
#Configuration
#EnableCaching
public class CacheConfig {
public CacheConfig() {
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().withCache("myCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(SimpleKey.class, String.class, ResourcePoolsBuilder.heap(10))).build();
cacheManager.init();
}
}
Error
But I'm getting the following error:
java.lang.IllegalArgumentException: Cannot find cache named 'myCache' for Builder...
I managed to get it to work if I put the config in the xml file, but I rather have it in java.
#Cacheable(value = "myCache") doesn't create a cache named myCache in Ehcache. At runtime, if a cache named myCache is available in Ehcache, it'll use that cache for caching. If not, when attempting to cache at runtime, the exception java.lang.IllegalArgumentException: Cannot find cache named 'myCache' will be thrown. For #Cacheable(value = "myCache") to work with Ehcache as the backend, the cache needs to be created somewhere and Spring needs to be made aware of that cache. The simplest way to do that is to include the spring-boot-starter-cache dependency, add an ehcache.xml with the Ehcache config to classpath and set the config spring.cache.jcache.config: classpath:ehcache.xml in application.yml. You can find a sample application that does that on github
Instead if you do want to configure Ehcache programmatically, you need a org.springframework.cache.CacheManager bean, to initialize the Ehcache config and link it to Spring. The bean definition could look something like below:
import javax.cache.Caching;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.jsr107.Eh107Configuration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.SimpleKey;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableCaching
public class CacheConfig {
#Bean
public CacheManager ehCacheManager() {
CacheConfiguration<SimpleKey, String> cacheConfig = CacheConfigurationBuilder
.newCacheConfigurationBuilder(SimpleKey.class, String.class, ResourcePoolsBuilder.heap(10))
.build();
javax.cache.CacheManager cacheManager = Caching.getCachingProvider("org.ehcache.jsr107.EhcacheCachingProvider")
.getCacheManager();
String cacheName = "myCache";
cacheManager.destroyCache(cacheName);
cacheManager.createCache(cacheName, Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfig));
return new JCacheCacheManager(cacheManager);
}
}
Sample working application that configures Ehcache for Spring through code can be found here on github.

spring-boot-starter-jdbc DAO repository object not injected in working legacy webservice

I am new in the spring/boot word and have a working JAX-WS based web-service declared in a springboot project. It is started and configured via web.xml and sun-jaxws.xml. So, no beans included there only endpoints declarations and servlet definitions and mappings.
I just now want to save the items i get in the webservice into the mysql database using spring-boot-starter-jdbc which is not working:
I can't achieve this as the repository is not injected in the webservice implementation.
Followed all steps in other question, but not achieving this!
Normally declaration of the datasource parameters in application.properties and annotating #webservice and #Repository would suffice to get the injection of the repository working in the webservice class. What am i missing ?
Here details of the steps I followed:
the webservice implementation is a package X and i created a #SpringBootApplication in order to use a mysql datasource declared in application.properties.
So i annotated the webservice as a #Component and the data access repository with #Repository and #Component
parent version: spring-boot-starter-parent : 1.5.10.RELEASE
webservice service implementation:
BServiceManager.java
package X;
....
#Component
#WebService(name = "***",***)
#BindingType("http://schemas.xmlsoap.org/wsdl/soap/http")
#XmlSeeAlso({
packagesxxx.class,
....
})
public class BServiceManager
implements xxxxx
{
....
#Autowired
private ItemRepository irepo;
....
#WebMethod(**)
#WebResult(***)
public ResponseDataInfo sendInfo( ){
....
trepo.saveitem(item)
....
}
}
ItemRepository.java
package Y.Z;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Component
#Repository
public class ItemRepository {
#Autowired
private JdbcTemplate jdbcTemplate ;
....
public boolean saveitem(Item item) {
....
}
}
Item.java
package Y.Z;
public class Item {
....
}
GetItemsApplication
package Y;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
//#ComponentScan(basePackages={"Y","Y.Z","X"})
#SpringBootApplication
public class GetItemsApplication {
....
public static void main(String[] args) {
SpringApplication.run(GetItemsApplication.class, args);
log.info("--Spring Boot inits done--");
}
}
application.properties
spring.data.jpa.repositories.enabled=false
spring.data.jdbc.repositories.enabled=true
# MySQL properties
spring.datasource.url=****
spring.datasource.username=****
spring.datasource.password=****
....
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
logging.level.org.springframework.jdbc.core.JdbcTemplate=debug
NB: even having datasource bean is not helping :
File: DataSourceConfig.java
package Y.Z;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
//#EnableJdbcRepositories for Spring
#Configuration
public class MDataSourceConfig {
#Bean
public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
return dataSourceBuilder.build();
}
#Bean
public JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
Your Webservice doesn't seem to get created by Spring.
Therefore Spring has no control over its dependencies, so you have to get the dependency programmatically.
There are many ways to do this.
Easy but not very elegant and uses global variables which might cause problems, especially with tests: https://stackoverflow.com/a/18486178/66686
More elegant but requires weaving Spring autowiring using #Configurable

How to enable connection pooling in spring boot embedded tomcat

I have a spring boot application which is not a web application. In this application i have configured embedded tomcat with the help of following bean.
#Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatWebServer(tomcat);
}
protected void postProcessContext(Context context) {
ContextResource contextResource = new ContextResource();
contextResource.setName("jdbc/BPMDB");
contextResource.setType(DataSource.class.getName());
contextResource.setProperty("driverClassName", env.getProperty("bpm.db.driverClassName"));
contextResource.setProperty("url", env.getProperty("bpm.db.url"));
contextResource.setProperty("username", env.getProperty("bpm.db.username"));
contextResource.setProperty("password", env.getProperty("bpm.db.password"));
context.getNamingResources().addResource(contextResource);
}
};
}
How do i do connection pooling for this embedded tomcat. I am using spring boot 2.x which says hikaricp is the default connection pooling but how to set it into this embedded tomcat.
Does this require to set properties like spring.datasource.hikari.initial-size=15
spring.datasource.hikari.max-wait=20000
but again how boot will know and how will i know that these properties are used.
Thanks.
I have got answer for my problem.
Its simple. We just have to make a DataSource reference and autowire it and mention database related properties along with hikari related properties.
Code is below.
#Autowired
public DataSource dataSource;
Add above to your #Configuration marked class and add following properties to application.properties file.
spring.datasource.driver-class=...
spring.datasource.url=jdbc:oracle:thin:....
spring.datasource.username=..
spring.datasource.password=..
spring.datasource.hikari.initial-size=15
spring.datasource.hikari.max-wait=20000
spring.datasource.hikari.max-active=50
spring.datasource.hikari.max-idle=50
spring.datasource.hikari.min-idle=8
Also i have written a test case to check for hikari connection pool. Below is the code.
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest(
properties = "spring.datasource.type=com.zaxxer.hikari.HikariDataSource",
classes = {ApplicationConfiguration.class,PersistenceJpaContext.class}
)
public class HikariConnectionPoolTest {
#Autowired
private DataSource dataSource;
#Test
public void hikariConnectionPoolIsConfigured() {
assertEquals("com.zaxxer.hikari.HikariDataSource", dataSource.getClass().getName());
}
}

Spring Boot Hibernate auto configuration vs manual annotated config

I have a Spring Boot Web app that tries to access my database using Hibernate.
I also have a different, none spring boot application that tries to access the same database.
I am trying to configure the spring boot application using the auto configuration approach, defining my DB properties in the application.properties file.
I am configuring the none spring boot app using an annotated class.
For some reason, the Spring Boots auto configuration is acting differently to the annotated class configuration.
If I connect to the database for the first time and create the schema using hibernate ddl, and then I reconnect using the other way of configuration, I get ddl errors, and for example enumerated columns stop working.
Can someone explain why I get different behaviour using the two ways of configuring spring and hibernate and how do I get them to act in the same way? Could this have something to do with the ejb naming strategy property?
Here are the two ways I'm configuring the JPA:
application.properties:
spring.datasource.url=jdbc:hsqldb:file:databaseFiles/hibData/;hsqldb.write_delay_millis=0
spring.datasource.root=sa
spring.datasource.password=1
spring.datasource.driverClassName=org.hsqldb.jdbcDriver
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true
Config class:
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
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 javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
public class DatabaseHibConfig {
#Bean
public DataSource getDataSource(){
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl("jdbc:hsqldb:file:databaseFiles/hibData/;hsqldb.write_delay_millis=0");
ds.setUsername("sa");
ds.setPassword("1");
return ds;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory, DataSource dataSource){
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(dataSource);
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan("mediabeast.data.hibernate.model");
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
jpaProperties.put("hibernate.hbm2ddl.auto","update");
jpaProperties.put("hibernate.show_sql","true");
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
}
adding the following properties to both configs seemed to fix the errors that stopped the code from working.
spring.jpa.properties.hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
however I am still getting the "object already exists" ddl errors on startup when switching configs.

Resources