I have Java - Spring Boot - Hibernate - Postgres application. And hibernate creates database connection every request, why? Is there configurable? For example, for one session to last 10 minutes?
My Hibernate configuration:
#Autowired
private Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "monitoring" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl(environment.getRequiredProperty("spring.datasource.url"));
dataSource.setUsername(environment.getRequiredProperty("spring.datasource.username"));
dataSource.setPassword(environment.getRequiredProperty("spring.datasource.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("spring.jpa.hibernate.show-sql"));
properties.put("hibernate.format_sql", "false");
properties.put("hibernate.jdbc.lob.non_contextual_creation", "true");
return properties;
}
And every request I'm getting following log:
11:19:13.584 [http-nio-8080-exec-2] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:postgresql://localhost:5432/monit]
Why? How can I change it?
You need to configure connection pools manually since you define a DataSource.
From Spring official documentation :
If you define your own DataSource bean, auto-configuration does not occur.
Starting from spring boot 2, HikariCP is the default Connection Pool embedded with spring boot starter (spring-boot-starter-jdbc and spring-boot-starter-data-jpa).
You can configure the maximum pool size with the following configuration with HikariCP
spring.datasource.hikari.maximum-pool-size= 10
I am getting this error while running my application : org.hibernate.service.UnknownUnwrapTypeException: Cannot unwrap to requested type [javax.sql.DataSource]
My configuration class :
#Configuration
#PropertySource("classpath:META-INF/spring/jdbc.properties")
public class HibernateConfig {
#Autowired
private Environment env;
#Bean(name="dataSource")
public DataSource getDataSource() throws PropertyVetoException{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(env.getProperty("db.driverClass"));
dataSource.setJdbcUrl(env.getProperty("db.jdbcUrl"));
dataSource.setUser(env.getProperty("db.user"));
dataSource.setPassword(env.getProperty("db.password"));
dataSource.setMaxPoolSize(50);
dataSource.setMinPoolSize(5);
dataSource.setMaxConnectionAge(1800);
dataSource.setMaxIdleTime(1800);
dataSource.setAutoCommitOnClose(false);
dataSource.setInitialPoolSize(5);
return dataSource;
}
#Bean(name="sessionFactory")
#Scope("singleton")
public LocalSessionFactoryBean getSessionFactory(DataSource dataSource){
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("db.dialect"));
hibernateProperties.setProperty("hibernate.jdbc.batch_size", "0");
hibernateProperties.setProperty("c3p0.acquire_increment", "1");
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
return localSessionFactoryBean;
}
#Bean(name="transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory){
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory);
return transactionManager;
}
}
I ran actually into this thread which talks about the same issue. However I am wondering if it is a sort of bug in hibernate5 that has not been fixed yet or does it relate to something else. Thank you in advance.
I'm trying to connect my Spring application to a Microsoft SQL Server database but I am getting the following error:
Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection] with root cause
java.security.cert.CertificateException: Certificates does not conform to algorithm constraints
I have already tried to remove the JDK's certpath setting to be blank like: jdk.certpath.disabledAlgorithms=
Here is my configuration:
#Configuration
#EnableJpaRepositories("com.abc.cet.eai.repository.sql")
#PropertySource("classpath:eai.application.properties")
public class JpaConfig {
#Bean
public DataSource dataSource() {
SQLServerDataSource dataSource = new SQLServerDataSource();
dataSource.setServerName("SERVERNAME");
dataSource.setUser("USERNAME");
dataSource.setPassword("PASSWORD");
dataSource.setDatabaseName("DATABASE_NAME");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setPackagesToScan("com.abc.cet.eai.domain");
factory.setDataSource(dataSource());
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setJpaProperties(additionalProperties());
return factory;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
public Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.SQLServer2008Dialect");
return properties;
}
}
Has anyone solved a similar problem?
You are basically experiencing the same issue as I did in WAGON-470. The certifacate with created with MD5 which is rejected by modern Java. You should inspect the certificate itself, the ciphers the server is offering and enable JSSE debug opts. IT is likely that you need to update/exchange your certificate wich a more secure method like SHA256.
I am trying to deploy my web app to Heroku. I have configured Hibernates (as the persistence provider) to do the following:
create schema based on entities;
fill data from sql script;
Here is my configuration:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(getDataSource());
entityManagerFactoryBean.setPackagesToScan("model");
entityManagerFactoryBean.setPersistenceProvider(new HibernatePersistenceProvider());
entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
return entityManagerFactoryBean;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setDataSource(getDataSource());
return transactionManager;
}
#Bean
public DataSource getDataSource() {
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;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.hbm2ddl.import_files", "test_data.sql");
return properties;
}
However, it seems that Hibernate cannot alter existing Heroku schema:
2016-07-16T15:04:20.978399+00:00 app[web.1]: 2016-07-16 15:04:20 ERROR SchemaExport:483 - HHH000389: Unsuccessful: alter table fueling drop constraint fuel_type
2016-07-16T15:04:20.975268+00:00 app[web.1]: 2016-07-16 15:04:20 ERROR SchemaExport:484 - ERROR: relation "customer" does not exist
2016-07-16T15:04:20.985169+00:00 app[web.1]: 2016-07-16 15:04:20 ERROR SchemaExport:484 - ERROR: relation "fueling" does not exist
Could you please advise what I am doing wrong?
I've been attempting to turn my JHipster generated application into a multi-tenancy app using this - http://jannatconsulting.com/blog/?p=41 blog post as a base.
I've run into a problem with second level caching. Spring boot appears to correctly detect and set up:
DatabaseConfiguration.java
#Configuration
#EnableConfigurationProperties(JpaProperties.class)
#EnableJpaRepositories(
entityManagerFactoryRef = "masterEntityManager",
transactionManagerRef = "masterTransactionManager",
basePackages = {"com.quadrimular.nts.helium.repository.master"})
#EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
#EnableTransactionManagement
#EnableElasticsearchRepositories("com.quadrimular.nts.helium.repository.search")
public class DatabaseConfiguration {
#Inject
private Environment env;
#Autowired(required = false)
private MetricRegistry metricRegistry;
#Inject
private DataSourceProperties datasourceProperties;
#Inject
private JHipsterProperties jhipsterProperties;
#Inject
private JpaProperties jpaProperties;
#Inject
private DataSource dataSource;
#Bean(destroyMethod = "close")
#ConditionalOnExpression("#{!environment.acceptsProfiles('cloud') && !environment.acceptsProfiles('heroku')}")
public DataSource dataSource(DataSourceProperties dataSourceProperties, JHipsterProperties jHipsterProperties) {
log.debug("Configuring Master Datasource");
if (dataSourceProperties.getUrl() == null) {
log.error("Your database connection pool configuration is incorrect! The application" +
" cannot start. Please check your Spring profile, current profiles are: {}",
Arrays.toString(env.getActiveProfiles()));
throw new ApplicationContextException("Database connection pool is not configured correctly");
}
HikariConfig config = new HikariConfig();
config.setDataSourceClassName(dataSourceProperties.getDriverClassName());
config.addDataSourceProperty("url", dataSourceProperties.getUrl());
if (dataSourceProperties.getUsername() != null) {
config.addDataSourceProperty("user", dataSourceProperties.getUsername());
} else {
config.addDataSourceProperty("user", ""); // HikariCP doesn't allow null user
}
if (dataSourceProperties.getPassword() != null) {
config.addDataSourceProperty("password", dataSourceProperties.getPassword());
} else {
config.addDataSourceProperty("password", ""); // HikariCP doesn't allow null password
}
//MySQL optimizations, see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
if ("com.mysql.jdbc.jdbc2.optional.MysqlDataSource".equals(dataSourceProperties.getDriverClassName())) {
config.addDataSourceProperty("cachePrepStmts", jHipsterProperties.getDatasource().isCachePrepStmts());
config.addDataSourceProperty("prepStmtCacheSize", jHipsterProperties.getDatasource().getPrepStmtCacheSize());
config.addDataSourceProperty("prepStmtCacheSqlLimit", jHipsterProperties.getDatasource().getPrepStmtCacheSqlLimit());
}
if (metricRegistry != null) {
config.setMetricRegistry(metricRegistry);
}
return new HikariDataSource(config);
}
#Bean(name = "masterEntityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource(datasourceProperties, jhipsterProperties));
em.setPackagesToScan(new String[]{"com.quadrimular.nts.helium.domain.master"});
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalJpaProperties());
em.setPersistenceUnitName("master");
return em;
}
private Properties additionalJpaProperties() {
Properties properties = new Properties();
for (Map.Entry<String, String> entry : jpaProperties.getHibernateProperties(dataSource).entrySet()) {
properties.setProperty(entry.getKey(), entry.getValue());
}
return properties;
}
#Bean(name = "masterTransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory masterEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(masterEntityManager);
return transactionManager;
}
}
When spring tries to configure:
MultiTenancyJPAConfiguration.java
#Configuration
#EnableConfigurationProperties(JpaProperties.class)
#EnableJpaRepositories(
entityManagerFactoryRef = "tenantEntityManager",
transactionManagerRef = "tenantTransactionManager",
basePackages = {"com.quadrimular.nts.helium.repository.tenant"})
#EnableTransactionManagement
public class MultiTenancyJpaConfiguration {
#Bean(name = "tenantEntityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
MultiTenantConnectionProvider connectionProvider,
CurrentTenantIdentifierResolver tenantResolver) {
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(dataSource);
emfBean.setPackagesToScan("com.quadrimular.nts.helium.domain.tenant");
emfBean.setJpaVendorAdapter(jpaVendorAdapter());
Map<String, Object> properties = new HashMap<>();
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
emfBean.setJpaPropertyMap(properties);
return emfBean;
}
#Bean(name = "tenantTransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(tenantEntityManager);
return transactionManager;
}
}
I'm getting this in my trace:
Caused by: org.hibernate.cache.NoCacheRegionFactoryAvailableException: Second-level cache is used in the application, but property hibernate.cache.region.factory_class is not given; please either disable second level cache or set correct region factory using the hibernate.cache.region.factory_class setting and make sure the second level cache provider (hibernate-infinispan, e.g.) is available on the classpath.
I have all the required properties defined in my application-dev.yml
hibernate.cache.use_second_level_cache: true
hibernate.cache.use_query_cache: false
hibernate.generate_statistics: true
hibernate.cache.region.factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
It appears that it's being read and used correctly by spring boot for my DatabaseConfiguration.java. I can't work out why it's not detecting the property file. If I try to disable the cache by setting:
hibernate.cache.use_second_level_cache: false
DatabaseConfiguration.java detects and behaves accordingly however MultiTenancyJPAConfiguration.java still throws the same exception.
Am I missing something obvious?
The answer is to actually set the jpa property values on the entity manager. I'm not sure how I overlooked this; I thought that somehow they were already set.
Firstly I injected the main datasource and the jpa properties object provided by spring boot if I'm not mistaken.
MultiTenancyJPAConfiguration.java
#Inject
private JpaProperties jpaProperties;
#Inject
private DataSource dataSource;
I then set the values using the same method used in DatabaseConfiguration.java
MultiTenancyJPAConfiguration.java
#Bean(name = "tenantEntityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
MultiTenantConnectionProvider connectionProvider,
CurrentTenantIdentifierResolver tenantResolver) {
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(dataSource);
emfBean.setPackagesToScan("com.quadrimular.nts.helium.domain.tenant");
emfBean.setJpaVendorAdapter(jpaVendorAdapter());
Map<String, Object> properties = new HashMap<>();
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
emfBean.setJpaPropertyMap(properties);
emfBean.setJpaProperties(additionalJpaProperties());
return emfBean;
}
private Properties additionalJpaProperties() {
Properties properties = new Properties();
for (Map.Entry<String, String> entry : jpaProperties.getHibernateProperties(dataSource).entrySet()) {
properties.setProperty(entry.getKey(), entry.getValue());
}
return properties;
}
Using the method additionalJpaProperties() to get all the hibernate jpa properties for my main datasource. I then set the hibernate property map properties after the hard coded ones. Clearly not the cleanest solution I plan to set all jpa values from the .yml file.