Connecting to heroku Postgres db with Java - java

I cannot connecting to heroku database, when I deploy my app to heroku I getting this on logs:
[localhost-startStop-1] WARN org.springframework.web.context.support.AnnotationConfigWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [path/DataBaseConfig.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
My database config:
public class DataBaseConfig {
#Resource
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws URISyntaxException{
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(env.getRequiredProperty("db.entity.package"));
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
em.setJpaProperties(getHibernateProperties());
return em;
}
#Bean
public BasicDataSource dataSource() throws URISyntaxException {
URI dbUri = new URI(System.getenv("jdbc:postgresql://user:password#Host:5432/databaseName"));
String username = dbUri.getUserInfo().split(":")[0];
String password = dbUri.getUserInfo().split(":")[1];
String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + ':' + dbUri.getPort() + dbUri.getPath();
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setUrl(dbUrl);
basicDataSource.setUsername(username);
basicDataSource.setPassword(password);
return basicDataSource;
}
}
What I do wrong?

Heroku uses DATABASE_URL environment variable to store the location of your primary database. So replace:
System.getenv("jdbc:postgresql://user:password#Host:5432/databaseName")
With:
System.getenv("DATABASE_URL")

If you are using the standard Java buildpack you can replace the code in your dataSource method with this:
String dbUrl = System.getenv("JDBC_DATABASE_URL");
String username = System.getenv("JDBC_DATABASE_USERNAME");
String password = System.getenv("JDBC_DATABASE_PASSWORD");
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setUrl(dbUrl);
basicDataSource.setUsername(username);
basicDataSource.setPassword(password);
return basicDataSource;
For more information see the Heroku documentation on Connecting to Relational Databases on Heroku with Java

It seems like you're using Spring! This answer is for Spring Boot users
Apart from DATABASE_URL, which is always there, Heroku creates 3 environment variables at Runtime. They are:
JDBC_DATABASE_URL
JDBC_DATABASE_USERNAME
JDBC_DATABASE_PASSWORD
As you may be aware, Spring Boot will automatically configure your database if it finds spring.datasource.* properties in your application.properties file. Here is an example of my application.properties
spring.datasource.url=${JDBC_DATABASE_URL}
spring.datasource.username=${JDBC_DATABASE_USERNAME}
spring.datasource.password=${JDBC_DATABASE_PASSWORD}
spring.jpa.show-sql=false
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
Hibernate / Postgres Dependencies
In my case I'm using Hibernate (bundled in spring-boot-starter-jpa with PostgreSQL, so I needed the right dependencies in my build.gradle:
dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile('org.postgresql:postgresql:9.4.1212')
}

Related

dataSource.setUsername(environment.getProperty("username") from file database.properties returns host user name

I have a simple dataSource() method to set datasource in Spring MVC using JDBC for PostgreSQL. I read database configuration from the resources.database.properties file. But it cannot read database username.
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Objects.requireNonNull(environment.getProperty("driver")));
dataSource.setUrl(environment.getProperty("url"));
dataSource.setUsername(environment.getProperty("username")); // - returns host username
dataSource.setPassword(environment.getProperty("password"));
return dataSource;
}
The resources.database.properties contains this:
driver=org.postgresql.Driver
url=jdbc:postgresql://172.17.0.2:5432/first_db
username=postgres
password=mypassword
If I hardcode the user name it works fine.
I just need to get my PostgreSQL user name (witch is running on my Docker container). What is wrong with this?
So there is a collision with another environment variable, "username". So you either rename the "username" in the properties or, even better, you can use a namespace:
database.driver=org.postgresql.Driver
database.url=jdbc:postgresql://172.17.0.2:5432/first_db
database.username=postgres
database.password=mypassword
Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Objects.requireNonNull(environment.getProperty("database.driver")));
dataSource.setUrl(environment.getProperty("database.url"));
dataSource.setUsername(environment.getProperty("database.username"));
dataSource.setPassword(environment.getProperty("database.password"));
return dataSource;

access two database from one spring boot application

I have two separate spring boot applications, app1 and app2. One is using mysql other one using postgresql as database source.
I need to access both database in app2 to query some data. Now, it would be easier if I can use the POJO from app1 to query and calculations when I am trying to access aap1's DB from app2. I found online that i can use multiple database in one spring boot application (https://www.baeldung.com/spring-data-jpa-multiple-databases).
Now, I am exporting the jar file from app1 with all the POJO and other classes and adding it to build path of app2. I am hoping this should work.
Then I tried everything what thay have mentioned in the above link
But I am getting following error
Description:
Parameter 0 of constructor in required a bean named 'entityManagerFactory' that could not be found.
Action:
Consider defining a bean named 'entityManagerFactory' in your
configuration.
Is it because I am using jar file instead of actual POJO?
Also, in app1, I am using "Sessionfactory" in DAO, though in app2, I am using cruderepository. Could this be issue?
Also, I have #EnableJpaRepositories annotation in main application.class. Should i comment it?
edit: After making suggested changes, I am getting following error:
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name '' defined in class path resource
[]: Unsatisfied dependency expressed through method ''
parameter 0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name '' defined in file
You need define the Bean like below:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws URISyntaxException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(<your_datasource>);
entityManagerFactoryBean.setPackagesToScan(package_to_scan);
//additional config of factory
return entityManagerFactoryBean;
}
#Bean(name = "transactionManager")
public PlatformTransactionManager jpaTransactionManager(EntityManagerFactory entityManagerFactory) throws URISyntaxException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}

How to prevent CommunicationsException?

I am currently working with an app which using two different DB(different instance).
DB A is totally under A's project, however DB B is under the other project.(I am managing these via gcloud app engine.)
What is my problem :
DB B always disconnected if no request more than few hours with below error message.
{"timestamp":1555464776769,"status":500,"error":"Internal Server Error","exception":"org.springframework.transaction.CannotCreateTransactionException","message":"Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: com.mysql.cj.jdbc.exceptions.CommunicationsException: The last packet successfully received from the server was 43,738,243 milliseconds ago. The last packet sent successfully to the server was 43,738,243 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.","path":"/client/getAllCompany"}
To resolve this issue, I tried.
1) add 'autoReconnect=true' at application.properties
api.datasource.url = jdbc:mysql://google/projectB?cloudSqlInstance=projectB:australia-southeast1:projectB&socketFactory=com.google.cloud.sql.mysql.SocketFactory&useSSL=false&autoReconnect=true
2) add below config at application.properties.
spring.datasource.tomcat.test-while-idle=true
spring.datasource.tomcat.time-between-eviction-runs-millis=3600000
spring.datasource.tomcat.min-evictable-idle-time-millis=7200000
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.validation-query=SELECT 1
(My project doesn't have web.xml file)
If i re-deploy this project, i can access data from DB B as well.
How can I config to prevent killed the connectivity with DB B?
Wish to listen advice. Thank you in advanced.
HibernateConfig Code for DB B
#Bean(name = "apiDataSource")
#ConfigurationProperties(prefix = "api.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "apiEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean apiEntityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("apiDataSource") DataSource dataSource
) {
return builder.dataSource(dataSource).packages("com.workspez.api.entity").persistenceUnit("api").build();
}
#Bean(name = "apiTransactionManager")
public PlatformTransactionManager apiTransactionManager(
#Qualifier("apiEntityManagerFactory") EntityManagerFactory apiEntityManagerFactory
) {
return new JpaTransactionManager(apiEntityManagerFactory);
}
#Bean(name = "apiJdbc")
public NamedParameterJdbcTemplate apiJdbcTemplate() {
return new NamedParameterJdbcTemplate(dataSource());
}

How to get a mysql connection from remote server in spring jdbc?

I am using db4free's mysql server for my spring-webmvc project.But the problem is , I can't get a connection to the server and the Exception is
org.springframework.web.util.NestedServletException: Request processing failed;
nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException:
Must specify port after ':' in connection string
But I have specified port correctly just after ':' , Here is my configuration java class:
#Configuration
#ComponentScan(basePackages="org.ratajo.amaderbari")
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://http://www.db4free.net:3306/myDB");
dataSource.setUsername("user");
dataSource.setPassword("pass");
return dataSource;
}
Here is the sample program I am trying to execute
MvcConfiguration mv = new MvcConfiguration();
JdbcTemplate jdbcTemplate = new JdbcTemplate(mv.getDataSource());
String sql="CREATE TABLE 'contact' ('contact_id' int(11) NOT NULL AUTO_INCREMENT,) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8";
jdbcTemplate.execute(sql);
The url looks weird :
dataSource.setUrl("jdbc:mysql://http://www.db4free.net:3306/myDB");
should be something like
dataSource.setUrl("jdbc:mysql://www.db4free.net:3306/myDB");
otherwise it is trying to use http as hostname and //www.db4free.net as port. (which explains the error). But I would also double check the hostname as it looks weird to go to a host 'www.something'.
OTOH jdbc url's are weird.

Configuring a JTA datasource for JBoss 8 (WildFly)

So, I read several times that if you use a Java EE container, you do not need to add environment params to an InitialContext in order to be able to use JNDI.
So I tried this:
#Bean
public DataSource dataSource() {
JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
return jndiDataSourceLookup.getDataSource("java:global/ExpensesDataSource");
}
However, retrieving a datasource using JNDI like this gives me a NoInitialContextException, telling me to specify the environment params.
Now, okay, so seems I was wrong to think it would work so flawlessly, so I tried retrieving the datasource like this:
#Bean
public DataSource dataSource() {
Properties jndiProperties = new Properties();
jndiProperties.setProperty(Context.PROVIDER_URL, "jnp://localhost:1099");
jndiProperties.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
jndiProperties.put("java.naming.factory.url.pkgs", "org.jboss.naming.org.jnp.interfaces");
JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
jndiDataSourceLookup.setJndiEnvironment(jndiProperties);
return jndiDataSourceLookup.getDataSource("java:global/ExpensesDataSource");
}
However this gives me a javax.naming.CommunicationException: Failed to connect to server localhost:1099
I've also tried just using localhost:1099 or localhost, none of them worked.
So my question is: do I even need to specify these properties, since JBoss 8 is a Java EE container to my knowledge. And if so, what provider url do I need to specify here?
If you use javax.naming.InitialContext, you don't need to specify environment params, just like you said. For example:
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:jboss/datasources/ExampleDS");
Not sure how JndiDataSourceLookup works..
For looking up a datasource, you can inject it using #Resource (inside an ejb context)
#Resource(name= "java:jboss/datasources/ExampleDS")
private Datasource ds;
Hope it helps!

Categories