Heroku - what change in code to use postgresql instead mysql - mysql

I prepared website in Spring/Maven with use of MySQL db, Tomcat. I decided to use Heroku free account, because I have domain, db and Java in one place. Problem is that Heroku uses postgresql for free but mysql is payable. I would like to ask you help and explanation clearly what I should change in my application's code(pom.xml, hibernate.properties etc) to use postgresql instead of mysql. Below I show files I think should be changed. Do I have to add any new files? I beg your indulgence.
***POM.XML***
jdbc.driver.class.name =com.mysql.jdbc.Driver
jdbc.url =jdbc:mysql://localhost:3306/web_users?useSSL=false&characterEncoding=UTF-8
jdbc.user.name =root
jdbc.password =root
hibernate.hbm2ddl.auto =update
hibernate.show_sql =true
hibernate.format_sql =true
hibernate.generate_statistics=false
***HibernateConfig.java***
#Configuration
#PropertySource(value = {"classpath:hibernate.properties"})
#EnableJpaRepositories(basePackages = "com.website.dao")
public class HibernateConfig {
#Autowired
private Environment environment;
// 1. create DataSource
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driver.class.name"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.user.name"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
return dataSource;
}
// 2. EntityManagerFactory
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", environment.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.show_sql", environment.getProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getProperty("hibernate.format_sql"));
properties.put("hibernate.generate_statistics", environment.getProperty("hibernate.generate_statistics"));
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPackagesToScan("com.website.model");
factoryBean.setJpaVendorAdapter(vendorAdapter);
factoryBean.setJpaProperties(properties);
factoryBean.setDataSource(dataSource());
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}

Related

Spring hibernate does not create mysql tables

I am implementing a backend with two database connections. One to a MS Access DB and another one to a MySQL DB. I've setup two configuration classes and the application is running without any error message, but does not create the tables for my entities in mysql db.
Project structure:
my.backend
|
--> configuration
--> controller
--> exceptions
--> model
| |
| --> mysql
| --> msaccess
|
--> repo
| |
| --> mysql
| --> msaccess
|
--> service
My configuration files are looking like this:
MySQL Configuration:
imports [...]
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "mysqlEntityManagerFactory",
transactionManagerRef = "mysqlTransactionManager",
basePackages = "my.backend.repo.mysql"
)
public class MySqlJpaConfig {
#Autowired
private Environment env;
#Bean
#Primary
#ConfigurationProperties(prefix = "mysql")
public LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(mysqlDataSource());
em.setPackagesToScan("my.backend.model.mysql");
em.setPersistenceUnitName("mysql");
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
HashMap<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put("hibernate.ddl-auto",
env.getProperty("mysql.jpa.hibernate.ddl-auto"));
jpaProperties.put("hibernate.dialect",
env.getProperty("mysql.jpa.properties.hibernate.dialect"));
em.setJpaPropertyMap(jpaProperties);
return em;
}
#Primary
#Bean
public DataSource mysqlDataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("mysql.url"));
dataSource.setUsername(env.getProperty("mysql.username"));
dataSource.setPassword(env.getProperty("mysql.password"));
dataSource.setDriverClassName(Objects.requireNonNull(env.getProperty("mysql.driver-class-name")));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager mysqlTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
mysqlEntityManagerFactory().getObject());
return transactionManager;
}
}
MS Access Configuration:
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "msaccessEntityManagerFactory",
transactionManagerRef = "msaccessTransactionManager",
basePackages = "my.backend.repo.msaccess"
)
#EnableTransactionManagement
public class MsAccessJpaConfig {
#Autowired
private Environment env;
#Bean
#ConfigurationProperties(prefix = "mysql")
public LocalContainerEntityManagerFactoryBean msaccessEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(msaccessDataSource());
em.setPackagesToScan("my.backend.model.msaccess");
em.setPersistenceUnitName("msaccess");
//em.setPersistenceProvider(new HibernatePersistenceProvider());
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
HashMap<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put("hibernate.dialect",
env.getProperty("msaccess.jpa.properties.hibernate.dialect"));
em.setJpaPropertyMap(jpaProperties);
return em;
}
#Bean
public DataSource msaccessDataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("msaccess.url"));
dataSource.setDriverClassName(Objects.requireNonNull(env.getProperty("msaccess.driver-class-name")));
return dataSource;
}
#Bean
public PlatformTransactionManager msaccessTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
msaccessEntityManagerFactory().getObject());
return transactionManager;
}
}
And my application.properties file:
spring.jpa.show-sql=true
spring.jpa.open-in-view=false
# MySQL config
mysql.url=jdbc:mysql://localhost:3306/my_database
mysql.username=
mysql.password=
mysql.driver-class-name=com.mysql.cj.jdbc.Driver
mysql.jpa.hibernate.ddl-auto=update
mysql.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# MS Access config
msaccess.url=jdbc:ucanaccess://c:/users/username/documents/test.accdb
msaccess.driver-class-name=net.ucanaccess.jdbc.UcanaccessDriver
msaccess.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServerDialect
When I run my application without the custom configuration and only one vanilla database connection (only MySQL) everything works fine. Also if I run this and perform a get request I get a Error that the table does not exist (obviously), so the connection to MySQL is there but the application just does not create the tables I need. Btw MS Access is working the same way, but I do not want a table generation there.
Am I missing some configuration for the connection?
Thanks for your help!
Cheers, niklas
My guess is that you have to use hibernate.hbm2ddl.auto instead of hibernate.ddl-auto in your jpa properties configuration, since that is the name hibernate looks for

configurationproperties is an unknown property

I am having problem understanding the usage of #ConfigurationProperties. In my application properties file, all of the variables "is an unknown property" with yellow underline. I run the application but the same thing happens. Is there a way to link the configuration at application.properties to my datasource function?
If I use
spring.datasource.url = jdbc:mysql://127.0.0.1/trs?useSSL=false
it works just fine but it i use app.datasource.url it wouldn't work
My application.properties file
# Primary DataSource configuration
app.datasource.url=jdbc:mysql://127.0.0.1/trs?useSSL=false
app.datasource.username=user
app.datasource.password=pass
my primary .java file
#ConfigurationProperties(prefix="app.datasource")
#Primary
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1/trs?useSSL=false");
dataSource.setUsername("user");
dataSource.setPassword("pass");
return dataSource;
}
For your application.properties, you need a corresponding java class to load the configuration in a bean. Like this -
#ConfigurationProperties(prefix="app.datasource")
#Component
public class DataSourceConfig{
private String url;
private String username;
private String password;
...
}
Now, where you want to use the DataSourceConfig bean, you can inject like this,
#Autowired
DataSourceConfig dataSourceConfig;
And once you have the object just do,
dataSourceConfig.getUrl();
dataSourceConfig.getUsername();
dataSourceConfig.getPassword();

Spring Boot Hikari Multiple Database Autowiring Failing

I am trying to implement multiple database with Spring Boot Hikari CP. I am getting
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: hikari_primary,hikari_secondary
For your reference I am attaching my spring boot datasource configuration files,
please dont go over primary and secondary naming conventions(they dont represent priorities), my requirement it to have two connection pool for two different databases.
Any help is appreciated
1.application.properties
spring.datasource.dataSourceClassName=com.microsoft.sqlserver.jdbc.SQLServerDataSource
primary.spring.datasource.url=jdbc:sqlserver://xxx.xxx.xxx.xxx:1433;DatabaseName=training
primary.spring.datasource.username=training
primary.spring.datasource.password=training
primary.spring.datasource.poolName=hikari_primary
primary.spring.datasource.maximumPoolSize=5
primary.spring.datasource.minimumIdle=3
primary.spring.datasource.maxLifetime=2000000
primary.spring.datasource.connectionTimeout=30000
primary.spring.datasource.idleTimeout=30000
primary.spring.datasource.pool-prepared-statements=true
primary.spring.datasource.max-open-prepared-statements=250
secondary.spring.datasource.url=jdbc:sqlserver://xxx.xxx.xxx.xxx:1433;DatabaseName=dev_xxxxx_core_v3
secondary.spring.datasource.username=developer
secondary.spring.datasource.password=Developer
secondary.spring.datasource.poolName=hikari_secondary
secondary.spring.datasource.maximumPoolSize=50
secondary.spring.datasource.minimumIdle=30
secondary.spring.datasource.maxLifetime=2000000
secondary.spring.datasource.connectionTimeout=30000
secondary.spring.datasource.idleTimeout=30000
secondary.spring.datasource.pool-prepared-statements=true
secondary.spring.datasource.max-open-prepared-statements=300
2. PrimaryDataSourceConfig.java
#Configuration
public class PrimaryDataSourceConfig {
#Value("${primary.spring.datasource.username}")
private String user;
#Value("${primary.spring.datasource.password}")
private String password;
#Value("${primary.spring.datasource.url}")
private String dataSourceUrl;
#Value("${spring.datasource.dataSourceClassName}")
private String dataSourceClassName;
#Value("${primary.spring.datasource.poolName}")
private String poolName;
#Value("${primary.spring.datasource.connectionTimeout}")
private int connectionTimeout;
#Value("${primary.spring.datasource.maxLifetime}")
private int maxLifetime;
#Value("${primary.spring.datasource.maximumPoolSize}")
private int maximumPoolSize;
#Value("${primary.spring.datasource.minimumIdle}")
private int minimumIdle;
#Value("${primary.spring.datasource.idleTimeout}")
private int idleTimeout;
#Bean(name="hikari_primary")
public HikariDataSource getHikariDataSourcePrimary() {
Properties dsProps = new Properties();
dsProps.put("url", dataSourceUrl);
dsProps.put("user", user);
dsProps.put("password", password);
Properties configProps = new Properties();
configProps.put("dataSourceClassName", dataSourceClassName);
configProps.put("poolName", poolName);
configProps.put("maximumPoolSize", maximumPoolSize);
configProps.put("minimumIdle", minimumIdle);
configProps.put("minimumIdle", minimumIdle);
configProps.put("connectionTimeout", connectionTimeout);
configProps.put("idleTimeout", idleTimeout);
configProps.put("dataSourceProperties", dsProps);
HikariConfig hc = new HikariConfig(configProps);
HikariDataSource ds = new HikariDataSource(hc);
return ds;
}
}
3. SecondayDataSourceConfig.java
#Configuration
public class SecondaryDataSourceConfig {
#Value("${secondary.spring.datasource.username}")
private String user;
#Value("${secondary.spring.datasource.password}")
private String password;
#Value("${secondary.spring.datasource.url}")
private String dataSourceUrl;
#Value("${spring.datasource.dataSourceClassName}")
private String dataSourceClassName;
#Value("${secondary.spring.datasource.poolName}")
private String poolName;
#Value("${secondary.spring.datasource.connectionTimeout}")
private int connectionTimeout;
#Value("${secondary.spring.datasource.maxLifetime}")
private int maxLifetime;
#Value("${secondary.spring.datasource.maximumPoolSize}")
private int maximumPoolSize;
#Value("${secondary.spring.datasource.minimumIdle}")
private int minimumIdle;
#Value("${secondary.spring.datasource.idleTimeout}")
private int idleTimeout;
#Bean(name="hikari_secondary")
public HikariDataSource getHikariDataSourceSecondary() {
Properties dsProps = new Properties();
dsProps.put("url", dataSourceUrl);
dsProps.put("user", user);
dsProps.put("password", password);
Properties configProps = new Properties();
configProps.put("dataSourceClassName", dataSourceClassName);
configProps.put("poolName", poolName);
configProps.put("maximumPoolSize", maximumPoolSize);
configProps.put("minimumIdle", minimumIdle);
configProps.put("minimumIdle", minimumIdle);
configProps.put("connectionTimeout", connectionTimeout);
configProps.put("idleTimeout", idleTimeout);
configProps.put("dataSourceProperties", dsProps);
HikariConfig hc = new HikariConfig(configProps);
HikariDataSource ds = new HikariDataSource(hc);
return ds;
}
}
4. Application.java
#SpringBootApplication
#ComponentScan("com.xxxx.springsql2o")
#EnableAutoConfiguration
public class Application
{
public static void main( String[] args )
{
SpringApplication.run(Application.class, args);
}
#Autowired
#Qualifier("hikari_primary")
DataSource hikariDataSourcePrimary;
#Autowired
#Qualifier("hikari_secondary")
DataSource hikariDataSourceSecondary;
#Bean(name= "primary_db")
public Sql2o getPrimarySql2o()
{
return new Sql2o(hikariDataSourcePrimary);
}
#Bean(name= "secondary_db")
public Sql2o getSecondarySql2o()
{
return new Sql2o(hikariDataSourceSecondary);
}
}
Spring boot is auto-configuring your application via #EnableAutoConfiguration (note that this annotation is already included in the composed #SpringBootApplication annotation). So my guess would be that you have some dependency that spring is trying to auto-configure (e.g. JPA) which uses/needs DataSource. If you can live with this, you can add #Primary to on of your DataSource Bean provider methods in order to satisfy that dependency.
So, for instance:
#Bean(name="hikari_primary")
#Primary
public HikariDataSource getHikariDataSourcePrimary() {...
Even if this should work, it would be recommended to remove auto-configuration for e.g. JPA or whatever spring boot is trying to auto-configure but you don't use/need and configure everything manually as it suits your application needs. Have two databases is certainly a custom configuration and does not conform to the spring boot easy-out-of-the-box approach.

How to create a database during spring context initialization

I need to create a database named test in my local mysql server which i will use to setup my datasource bean. I am using the following spring configuration for setting up the datasource and jdbctemplate for my testing
#Configuration
class Config {
#Bean(initMethod = "setupDatabase")
public DataSource getDataSource() {
String url = "jdbc:mysql://localhost:3306/test";
DriverManagerDataSource dataSource = new DriverManagerDataSource(
url, settings.getUsername(), settings.getPassword());
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
#Bean
public JdbcTemplate getJdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(((DataSourceTransactionManager)transactionManager()).getDataSource());
return jdbcTemplate;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(getDataSource());
}
#Bean
public DataSourceInitializer dataSourceInitializer(final DataSource dataSource) {
final DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(databasePopulator());
return initializer;
}
private DatabasePopulator databasePopulator() {
final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(schemaScript);
return populator;
}
#PostConstruct
public void setupDatabase() {
String url = "jdbc:mysql://localhost:3306";
try {
Connection connection = DriverManager.getConnection(url, settings.getUsername(), settings.getPassword());
Statement statement = connection.createStatement();
statement.execute("create database test");
} catch (SQLException exception) {
LOGGER.error("Could not setup database for test", exception);
throw new RuntimeException(exception);
}
}
}
I am getting the following error Caused by:
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database 'test'
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)
at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:46)
Can someone explain what is going wrong with this configuration?
Did you create the test database at your local mysql? You need to create the db first to connect from your application. If you want to create a database by executing sql query connect to the database as root user and create the db.
The source of the exception: your setupDatabase() method is executed actually by Spring AFTER getDataSource() cause #Bean(initMethod = "setupDatabase") forces Spring to execute initMetod AFTER a bean creation for the bean initialization. But it's not you expect here.
You need somehow define your getDataSource() is depended on setupDatabase(). E.g. with a help of #DependsOn annotation.
Also see Spring 3 bean instantiation sequence
P.S. but why you don't simple manually add setupDatabase() call into getDataSource() method?

Vaadin 7 & Spring Boot : SqlContainer doesnot work with Filter

Spring Boot: 1.3.2.RELEASE
Vaadin : 7.6.3
Mysql: mysql-java-connector-5.1.38
HikariCP: 2.4.3
So I create a Table with only id and name columns. Then a vaadin componant Table to show the content of table. Until now everything is fine. Then I tried to filter the table with a vaadin Filter, and it works if the connection pool is com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool, and doesnot if it is com.vaadin.data.util.sqlcontainer.connection.J2EEConnectionPool which I use HikariCP as the data source.
DBConfig.java
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
public HikariConfig hikariConfig() {
HikariConfig config = new HikariConfig();
config.setDriverClassName("com.mysql.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false");
config.setUsername("root");
config.setPassword("root");
config.setMaximumPoolSize(20);
config.setPoolName("connectionPool");
return config;
}
#Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource(hikariConfig());
return dataSource;
}
ApplicationUI.java
#Autowired
private J2EEConnectionPool connectionPool;
#Override
protected void init(VaadinRequest arg0) {
TableQuery tq = new TableQuery("medecine", connectionPool);// it does not work if I use HikariCP as the J2EEConnectionPool
JDBCConnectionPool pool = new SimpleJDBCConnectionPool("com.mysql.jdbc.Driver",
"jdbc:mysql://localhost:3306/test?autoReconnect=true&useSSL=false", "root", "root");
TableQuery tq = new TableQuery("medecine", connectionPool);// it works if I use **SimpleJDBCConnectionPool**.
container = new SQLContainer(tq);
table = new Table();
table.setContainerDataSource(container);
table.setWidth(100, Unit.PERCENTAGE);
mainLayout.addComponent(table);
Button addFilter = new Button("filter", new ClickListener() {
private static final long serialVersionUID = -7071683058766115266L;
#Override
public void buttonClick(ClickEvent arg0) {
Filter filter = new SimpleStringFilter("name", "medecine2", true, false);
container.addContainerFilter(filter);
}
});
mainLayout.addComponent(addFilter);
}
The reason I choose HikariCP as the data source is for a better performance and I'm not sure that the vaadin connection pool will be better than HikariCP. Or, it is limited to vaadin connection pool for the filtering function?