Spring Boot #DataJpaTest without ddl generation - java

I have MySQL with tables in two databases and want to write a test with SpringBoot (1.5.6.RELEASE) and JPA. For this, I use the #DataJpaTest together with #EntityScan, as the entities are in two different packages. As embedded database for the test, I use H2.
My first problem was, that Spring Boot threw an exception that the schemas were not found, therefore I created a schema.sql with two CREATE SCHEMA IF NOT EXISTS statements like described in this question.
However, I also wanted to insert some test data and added a data.sql file. The problem was now, that Spring boot first executed the schema.sql, then the data.sql and following this Hibernate again created the tables, which eventually resulted in empty tables. To solve this problem, I tried to set spring.jpa.hibernate.ddl-auto=none within the application.properties. However, Hibernate now started to switch naming strategies and converted camelCase to sneak_case, which again resulted in errors. So I guess, this is not the way how it should be done. I also tried spring.jpa.generate-ddl=false, but this did not have any effect.
How is it possible to deactivate the automatic DDL generation (only use schema.sql and data.sql) and at the same time use #DataJpaTest?
Thank you very much!

Solution 1: properties/yaml file
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
jackson:
serialization:
indent_output: true
datasource:
driver-class-name: org.hsqldb.jdbcDriver
generate-unique-name: true
jpa:
hibernate:
ddl-auto: none
show-sql: true
h2:
console:
enabled: false
liquibase:
change-log: classpath:/liquibase/db.changelog-master.xml
drop-first: true
contexts: QA
Solution 2: override #Bean
#Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, Environment env) {
final LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factory.setPackagesToScan("com.spring.web.demo.persistent.entity");
factory.setJpaProperties(jpaProperties(env));
return factory;
}
private Properties jpaProperties(Environment env) {
final Properties properties = new Properties();
properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
//!!!: see here
properties.put("hibernate.hbm2ddl.auto", "none");
properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", false);
properties.put("hibernate.physical_naming_strategy", PhysicalNamingStrategyStandardImpl.class.getName());
properties.put("hibernate.generate_statistics", true);
properties.put("hibernate.cache.use_second_level_cache", true);
properties.put("hibernate.cache.use_query_cache", true);
properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
return properties;
}
Note, that application.properies or application.yaml should be under test/resources and your #Configuration class with #Bean should be used by tests.
For test via sql-files you could use EmbeddedDataSource
There are some examples at my github

you can create another application.properties and configure file for under test directory.
for other problem use flyway after db creation flyway scripts which is your insert scripts run automatically.

Related

Spring boot quartz schema other than public doesn't work

I am not able to use other schema (than public) for quartz tables. This is my quartz setup:
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=always
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=2000
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
spring.quartz.properties.org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.useProperties=false
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
And config class:
#Bean
public SchedulerFactoryBean schedulerFactory(ApplicationContext applicationContext, DataSource dataSource, QuartzProperties quartzProperties) {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
AutowireCapableBeanJobFactory jobFactory = new AutowireCapableBeanJobFactory(applicationContext.getAutowireCapableBeanFactory());
Properties properties = new Properties();
properties.putAll(quartzProperties.getProperties());
schedulerFactoryBean.setOverwriteExistingJobs(true);
schedulerFactoryBean.setDataSource(dataSource);
schedulerFactoryBean.setQuartzProperties(properties);
schedulerFactoryBean.setJobFactory(jobFactory);
return schedulerFactoryBean;
}
#Bean
public Scheduler scheduler(ApplicationContext applicationContext, DataSource dataSource, QuartzProperties quartzProperties)
throws SchedulerException {
Scheduler scheduler = schedulerFactory(applicationContext, dataSource, quartzProperties).getScheduler();
scheduler.start();
return scheduler;
}
This works fine, and the tables are getting created. However I would like to have the tables in a different schema. So I set quartz to use 'quartz' schema.
spring.quartz.properties.org.quartz.jobStore.tablePrefix=quartz.QRTZ_
This is the error I'm getting:
[ClusterManager: Error managing cluster: Failure obtaining db row lock: ERROR: current transaction is aborted, commands ignored until end of transaction block] [org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: ERROR: current transaction is aborted, commands ignored until end of transaction block
Any ideas on how to solve it?
It was a bold hope that "tablePrefix" can also adjsut the "db schema", (and there is no documented property concerning "db schema"), but you could get more lucky, if you configure it on the datasource.
i.e. you would introduce/configure different (spring) datasource( bean)s for every user/schema used by your application ...
(like here:) Spring Boot Configure and Use Two DataSources
or here
, then you'd wire the scheduler factory with the appropriate datasource (quartz).
schedulerFactoryBean.setDataSource(quartzDataSource);
Or via (#Autowired) parameter injection, or method invocation : #Bean initialization - difference between parameter injection vs. direct method access?
UPDATE (regarding "wiring"):
..from current spring-boot doc:
To have Quartz use a DataSource other than the application’s main DataSource, declare a DataSourcebean, annotating its #Bean method with #QuartzDataSource. Doing so ensures that the Quartz-specific DataSource is used by both the SchedulerFactoryBean and for schema initialization.
Similarly, to have Quartz use a TransactionManager other than the application’s main ... declare a TransactionManager bean, ...#QuartzTransactionManager.
You can take even more control by customizing:
spring.quartz.jdbc.initialize-schema
Database schema initialization mode.
default: embedded (embedded|always|never)
spring.quartz.jdbc.schema
Path to the SQL file to use to initialize the database schema.
default: classpath:org/quartz/impl/jdbcjobstore/tables_##platform##.sql
... properties, where ##platform## refers to your db vendor.
But it is useless for your requirement... since looking at
and complying with the original schemes - they seem schema independent/free. (So the data source approach looks more promising, herefor.)
REFS:
https://www.quartz-scheduler.org/documentation/quartz-2.3.0/configuration/ConfigJobStoreTX.html
Spring Boot Configure and Use Two DataSources
https://stackoverflow.com/a/42360877/592355
https://www.baeldung.com/spring-annotations-resource-inject-autowire
#Bean initialization - difference between parameter injection vs. direct method access?
spring.quartz.jdbc.initialize-schema
What are the possible values of spring.datasource.initialization-mode?
spring.quartz.jdbc.schema
https://github.com/quartz-scheduler/quartz/tree/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.quartz
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/quartz/QuartzDataSource.html
So the idea is that Quartz doesn't create the tables using spring.quartz.properties.org.quartz.jobStore.tablePrefix
Table names are static. Eg qrtz_triggers. as #xerx593 pointed out.
What we can do is to create the tables (manual, flyway, liquibase) in a different schema, update tablePrefix=schema.qrtz_ and it will work.
Tested with Postgres

setup alternate datasource in spring boot application causes liquibase to fail

Application has a default spring data source specified in application.yml
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:oracle:thin:#localhost:1521:xe
username: system
password: oracle
hikari:
poolName: Hikari
auto-commit: false
I have added configuration options for a second data source, used for a completely difference (JDBCTemplate purpose).
faas20:
ds:
url: jdbc:oracle:thin:#tldb0147vm.group.net:1760:tdb
username: ...
password: ...
Then, I add two data sources, one named, and the other default. Without the default one, liquibase fails to start.
#Configuration
public class LegacyConfiguration {
#Bean(name = "faas20")
#ConfigurationProperties(prefix = "faas20.ds")
public DataSource legacyDataSource() {
return DataSourceBuilder
.create()
.build();
}
#Bean
public DataSource defaultDataSource() {
return DataSourceBuilder
.create()
.build();
}
}
Startup of the application fails though.
The application now cannot build the default EntityManagerFactory.
Why would that be affected?
Parameter 0 of constructor in impl.OrderServiceImpl required a bean named 'entityManagerFactory' that could not be found.
Consider defining a bean named 'entityManagerFactory' in your configuration.
Without the two data sources present the application and liquibase start up as they should.
edit
I am not clear on how to configure two separate data sources,
Default Data Source for JPA
Additional Data Source for use in JDBC (and potentially other JPA classes)

Hibernate ImprovedNamingStrategy doesn't work

I have a database with columns naming using snakecase and entities where columns named in camelcase. The project was written using spring boot and had this configuration:
#Primary
#Bean
public LocalContainerEntityManagerFactoryBean mainEntityManagerFactory(
#Qualifier("mainDataSource") DataSource mainDataSource,
#Qualifier("mainJpaProperties") JpaProperties mainJpaProperties) {
AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(mainJpaProperties.isShowSql());
adapter.setDatabase(mainJpaProperties.getDatabase());
adapter.setDatabasePlatform(mainJpaProperties.getDatabasePlatform());
adapter.setGenerateDdl(mainJpaProperties.isGenerateDdl());
Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.putAll(mainJpaProperties.getHibernateProperties(mainDataSource));
jpaProperties.put("jpa.hibernate.naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy");
return new EntityManagerFactoryBuilder(adapter, mainJpaProperties, persistenceUnitManager)
.dataSource(mainDataSource)
.packages(Employee.class)
.properties(jpaProperties)
.persistenceUnit("main")
.jta(false)
.build();
}
this is application.properties content:
jpa.hibernate.hbm2ddl.auto=none
jpa.hibernate.ddlAuto=none
jpa.hibernate.naming_strategy = org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
jpa.generateDdl=false
jpa.showSql=false
jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
Now I can't use spring boot and trying to convert configuration:
#Primary
#Bean
public LocalContainerEntityManagerFactoryBean mainEntityManagerFactory(
#Qualifier("mainDataSource") DataSource mainDataSource
) {
AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(Boolean.valueOf(environment.getProperty("jpa.showSql")));
adapter.setDatabase(Database.POSTGRESQL);
adapter.setDatabasePlatform(environment.getProperty("jpa.hibernate.dialect"));
adapter.setGenerateDdl(Boolean.valueOf(environment.getProperty("jpa.generateDdl")));
Properties jpaProperties = new Properties();
jpaProperties.put("jpa.hibernate.dialect", environment.getProperty("jpa.hibernate.dialect"));
jpaProperties.put("hibernate.naming_strategy", "main.util.NamingStrategy");
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(mainDataSource);
factoryBean.setJpaVendorAdapter(adapter);
factoryBean.setPersistenceUnitName("main");
factoryBean.setPersistenceUnitManager(persistenceUnitManager);
factoryBean.setJpaProperties(jpaProperties);
factoryBean.setPackagesToScan(packageToScan);
factoryBean.afterPropertiesSet();
return factoryBean;
}
main.util.NamingStrategy is just a copypaste of org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy.
When I trying to run it it looks like that this naming strategy doesn't work because I get an error:
org.hibernate.AnnotationException:
Unable to create unique key constraint (emp_address_id, year, yearNumber)
on table employeedata:
database column 'emp_address_id' not found.
Make sure that you use the correct column name which depends
on the naming strategy in use
(it may not be the same as the property name in the entity,
especially for relational types)
How can I make this work without spring boot?
Just to put it explicitly(as i had to spend some time figuring it out from Maciej's answer), this works for me on Hibernate 5.x:
properties.put("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
jpa.hibernate.naming_strategy property key is used only in Spring Boot's configuration.
When you configure hibernate by yourself you should use Hibernate properties instead. Proper name of Hibernate naming strategy property key is
hibernate.ejb.naming_strategy
Try to replace it in your jpaProperties object:
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.dialect", environment.getProperty("jpa.hibernate.dialect")); //jpa dialect property key is different too
jpaProperties.put("hibernate.ejb.naming_strategy", "main.util.NamingStrategy");
List of all miscellaneous properties:
https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#configuration-misc-properties
I am assuming that you only removed Spring Boot and you are still using Hibernate 4.x (in Hibernate 5.x NamingStrategy was replaced with ImplicitNamingStrategy and PhysicalNamingStrategy)
For hibernate 5.x you should use org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNam‌​ingStrategy and default Hibernate's ImplicitNamingStrategy:
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-1.4-Release-Notes#naming-strategy
Configuration key for this physical naming strategy is: hibernate.physical_naming_strategy

Spring Boot - Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set [duplicate]

I am trying run a spring-boot application which uses hibernate via spring-jpa, but i am getting this error:
Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:104)
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:71)
at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:205)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:111)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:234)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:206)
at org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1885)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1843)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:398)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1613)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1550)
... 21 more
my pom.xml file is this:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
</dependencies>
my hibernate configuration is that (the dialect configuration is in the last method from this class):
#Configuration
#EnableTransactionManagement
#ComponentScan({ "com.spring.app" })
public class HibernateConfig {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.spring.app.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource restDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/teste?charSet=LATIN1");
dataSource.setUsername("klebermo");
dataSource.setPassword("123");
return dataSource;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties hibernateProperties() {
return new Properties() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
setProperty("hibernate.hbm2ddl.auto", "create");
setProperty("hibernate.show_sql", "false");
setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
}
};
}
}
what I am doing wrong here?
First remove all of your configuration Spring Boot will start it for you.
Make sure you have an application.properties in your classpath and add the following properties.
spring.datasource.url=jdbc:postgresql://localhost:5432/teste?charSet=LATIN1
spring.datasource.username=klebermo
spring.datasource.password=123
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=create
If you really need access to a SessionFactory and that is basically for the same datasource, then you can do the following (which is also documented here although for XML, not JavaConfig).
#Configuration
public class HibernateConfig {
#Bean
public HibernateJpaSessionFactoryBean sessionFactory(EntityManagerFactory emf) {
HibernateJpaSessionFactoryBean factory = new HibernateJpaSessionFactoryBean();
factory.setEntityManagerFactory(emf);
return factory;
}
}
That way you have both an EntityManagerFactory and a SessionFactory.
UPDATE: As of Hibernate 5 the SessionFactory actually extends the EntityManagerFactory. So to obtain a SessionFactory you can simply cast the EntityManagerFactory to it or use the unwrap method to get one.
public class SomeHibernateRepository {
#PersistenceUnit
private EntityManagerFactory emf;
protected SessionFactory getSessionFactory() {
return emf.unwrap(SessionFactory.class);
}
}
Assuming you have a class with a main method with #EnableAutoConfiguration you don't need the #EnableTransactionManagement annotation, as that will be enabled by Spring Boot for you. A basic application class in the com.spring.app package should be enough.
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Something like that should be enough to have all your classes (including entities and Spring Data based repositories) detected.
UPDATE: These annotations can be replaced with a single #SpringBootApplication in more recent versions of Spring Boot.
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
I would also suggest removing the commons-dbcp dependency as that would allow Spring Boot to configure the faster and more robust HikariCP implementation.
I was facing a similar problem when starting up the application (using Spring Boot) with the database server down.
Hibernate can determine the correct dialect to use automatically, but in order to do this, it needs a live connection to the database.
add spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect in application.properties file
I got this error when my database was not created. After creating the DB manually, it worked fine.
I also faced a similar issue. But, it was due to the invalid password provided. Also, I would like to say your code seems to be old-style code using spring. You already mentioned that you are using spring boot, which means most of the things will be auto configured for you. hibernate dialect will be auto selected based on the DB driver available on the classpath along with valid credentials which can be used to test the connection properly. If there is any issue with the connection you will again face the same error. only 3 properties needed in application.properties
# Replace with your connection string
spring.datasource.url=jdbc:mysql://localhost:3306/pdb1
# Replace with your credentials
spring.datasource.username=root
spring.datasource.password=
Remove the redundant Hibernate Configuration
If you're using Spring Boot, you don't need to provide the JPA and Hibernate configuration explicitly, as Spring Boot can do that for you.
Add database configuration properties
In the application.properties Spring Boot configuration file, you have the add your database configuration properties:
spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://localhost:5432/teste
spring.datasource.username = klebermo
spring.datasource.password = 123
Add Hibernate specific properties
And, in the same application.properties configuration file, you can also set custom Hibernate properties:
# Log SQL statements
spring.jpa.show-sql = false
# Hibernate ddl auto for generating the database schema
spring.jpa.hibernate.ddl-auto = create
# Hibernate database Dialect
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
That's it!
I ran into the same problem and my issue was that the DB I was trying to connect to didn't exist.
I created the DB, verified the URL/connection string and reran and everything worked as expected.
I had same issue. adding this to the application.properties solved the issue:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
The following are some of the reasons for the hibernate.dialect not set issue.
Most of these exceptions are shown in the startup log which is finally followed by the mentioned issue.
Example: In Spring boot app with Postgres DB
1. Check if the database is actually installed and its server is started.
org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
java.net.ConnectException: Connection refused: connect
org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
2. Check if the database name is correctly mentioned.
org.postgresql.util.PSQLException: FATAL: database "foo" does not exist
In application.properties file,
spring.datasource.url = jdbc:postgresql://localhost:5432/foo
but foo didn't exist.
So I created the database from pgAdmin for postgres
CREATE DATABASE foo;
3. Check if the host name and server port is accessible.
org.postgresql.util.PSQLException: Connection to localhost:5431 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
java.net.ConnectException: Connection refused: connect
4. Check if the database credentials are correct.
as #Pankaj mentioned
org.postgresql.util.PSQLException: FATAL: password authentication failed for user "postgres"
spring.datasource.username= {DB USERNAME HERE}
spring.datasource.password= {DB PASSWORD HERE}
In spring boot for jpa java config you need to extend JpaBaseConfiguration and implement it's abstract methods.
#Configuration
public class JpaConfig extends JpaBaseConfiguration {
#Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
return vendorAdapter;
}
#Override
protected Map<String, Object> getVendorProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
}
}
this is happening because your code is not bale to connect the database. Make sure you have mysql driver and username, password correct.
Make sure your application.properties has all correct info: (I changed my db port from 8889 to 3306 it worked)
db.url: jdbc:mysql://localhost:3306/test
It turns out there is no one mentioning set spring.jpa.database=mysql in application.properties file, if you use Spring JPA. This is the simplest answer to me and I want to share in this question.
In my case the user could not connect to the database. If will have same issue if the log contains a warning just before the exception:
WARN HHH000342: Could not obtain connection to query metadata : Login failed for user 'my_user'.
Make sure you have your database in your pom like OP did. That was my problem.
My problem was that embedded database was already connected. close connection
I got this issue when Eclipse was unable to find the JDBC driver. Had to do a gradle refresh from the eclipse to get this work.
I had the same issue and after debugging it turns out that Spring application.properties had wrong IP address for DB server
spring.datasource.url=jdbc:oracle:thin:#WRONG:1521/DEV
If you are using this line:
sessionFactory.getHibernateProperties().put("hibernate.dialect", env.getProperty("hibernate.dialect"));
make sure that env.getProperty("hibernate.dialect") is not null.
Same but in a JBoss WildFly AS.
Solved with properties in my META-INF/persistence.xml
<properties>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<property name="spring.jpa.database-platform" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="spring.jpa.show-sql" value="false" />
</properties>
For those working with AWS MySQL RDS, it may occur when you are unable to connect to the database. Go to AWS Security Groups setting for MySQL RDS and edit the inbound IP rule by refreshing MyIP.
I faced this issue and doing above got the problem fixed for me.
I also had this problem. In my case it was because of no grants were assigned to MySQL user. Assigning grants to MySQL user which my app uses resolved the issue:
grant select, insert, delete, update on my_db.* to 'my_user'#'%';
Adding spring.jpa.database-platform=org.hibernate.dialect.MariaDB53Dialect to my properties file worked for me.
PS: i'm using MariaDB
I reproduced this error message in the following three cases:
There does not exist database user with username written in application.properties file or persistence.properties file or, as in your case, in HibernateConfig file
The deployed database has that user but user is identified by different password than that in one of above files
The database has that user and the passwords match but that user does not have all privileges needed to accomplish all database tasks that your spring-boot app does
The obvious solution is to create new database user with the same username and password as in the spring-boot app or change username and password in your spring-boot app files to match an existing database user and grant sufficient privileges to that database user. In case of MySQL database this can be done as shown below:
mysql -u root -p
>CREATE USER 'theuser'#'localhost' IDENTIFIED BY 'thepassword';
>GRANT ALL ON *.* to theuser#localhost IDENTIFIED BY 'thepassword';
>FLUSH PRIVILEGES;
Obviously there are similar commands in Postgresql but I haven't tested if in case of Postgresql this error message can be reproduced in these three cases.
I had the same issue and it was caused by being unable to connect to the database instance. Look for hibernate error HHH000342 in the log above that error, it should give you an idea to where the db connection is failing (incorrect username/pass, url, etc.)
This happened to me because I hadn't added the conf.configure(); before beginning the session:
Configuration conf = new Configuration();
conf.configure();
Make sure that you have enter valid detail in application.properties and whether your database server is available. As a example when you are connecting with MySQL check whether XAMPP is running properly.
I faced the same issue: The db I was trying to connect did not exist. I used jpa.database=default (which I guess means it will try to connect to the database and then auto select the dialect). Once I started the database, it worked fine without any change.
I faced this issue due to Mysql 8.0.11 version reverting back to 5.7 solved for me
I had the same error after using the hibernate code generation
https://www.mkyong.com/hibernate/how-to-generate-code-with-hibernate-tools/
then the hibernate.cfg.xml was created in /src/main/java
but without the connection parameters
after removing it - my problem was solved

org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set

I am trying run a spring-boot application which uses hibernate via spring-jpa, but i am getting this error:
Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:104)
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:71)
at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:205)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:111)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:234)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:206)
at org.hibernate.cfg.Configuration.buildTypeRegistrations(Configuration.java:1885)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1843)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:843)
at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:398)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:842)
at org.hibernate.jpa.HibernatePersistenceProvider.createContainerEntityManagerFactory(HibernatePersistenceProvider.java:152)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:336)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1613)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1550)
... 21 more
my pom.xml file is this:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
</dependencies>
my hibernate configuration is that (the dialect configuration is in the last method from this class):
#Configuration
#EnableTransactionManagement
#ComponentScan({ "com.spring.app" })
public class HibernateConfig {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.spring.app.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource restDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/teste?charSet=LATIN1");
dataSource.setUsername("klebermo");
dataSource.setPassword("123");
return dataSource;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties hibernateProperties() {
return new Properties() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
setProperty("hibernate.hbm2ddl.auto", "create");
setProperty("hibernate.show_sql", "false");
setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
}
};
}
}
what I am doing wrong here?
First remove all of your configuration Spring Boot will start it for you.
Make sure you have an application.properties in your classpath and add the following properties.
spring.datasource.url=jdbc:postgresql://localhost:5432/teste?charSet=LATIN1
spring.datasource.username=klebermo
spring.datasource.password=123
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=create
If you really need access to a SessionFactory and that is basically for the same datasource, then you can do the following (which is also documented here although for XML, not JavaConfig).
#Configuration
public class HibernateConfig {
#Bean
public HibernateJpaSessionFactoryBean sessionFactory(EntityManagerFactory emf) {
HibernateJpaSessionFactoryBean factory = new HibernateJpaSessionFactoryBean();
factory.setEntityManagerFactory(emf);
return factory;
}
}
That way you have both an EntityManagerFactory and a SessionFactory.
UPDATE: As of Hibernate 5 the SessionFactory actually extends the EntityManagerFactory. So to obtain a SessionFactory you can simply cast the EntityManagerFactory to it or use the unwrap method to get one.
public class SomeHibernateRepository {
#PersistenceUnit
private EntityManagerFactory emf;
protected SessionFactory getSessionFactory() {
return emf.unwrap(SessionFactory.class);
}
}
Assuming you have a class with a main method with #EnableAutoConfiguration you don't need the #EnableTransactionManagement annotation, as that will be enabled by Spring Boot for you. A basic application class in the com.spring.app package should be enough.
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Something like that should be enough to have all your classes (including entities and Spring Data based repositories) detected.
UPDATE: These annotations can be replaced with a single #SpringBootApplication in more recent versions of Spring Boot.
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
I would also suggest removing the commons-dbcp dependency as that would allow Spring Boot to configure the faster and more robust HikariCP implementation.
I was facing a similar problem when starting up the application (using Spring Boot) with the database server down.
Hibernate can determine the correct dialect to use automatically, but in order to do this, it needs a live connection to the database.
add spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect in application.properties file
I got this error when my database was not created. After creating the DB manually, it worked fine.
I also faced a similar issue. But, it was due to the invalid password provided. Also, I would like to say your code seems to be old-style code using spring. You already mentioned that you are using spring boot, which means most of the things will be auto configured for you. hibernate dialect will be auto selected based on the DB driver available on the classpath along with valid credentials which can be used to test the connection properly. If there is any issue with the connection you will again face the same error. only 3 properties needed in application.properties
# Replace with your connection string
spring.datasource.url=jdbc:mysql://localhost:3306/pdb1
# Replace with your credentials
spring.datasource.username=root
spring.datasource.password=
Remove the redundant Hibernate Configuration
If you're using Spring Boot, you don't need to provide the JPA and Hibernate configuration explicitly, as Spring Boot can do that for you.
Add database configuration properties
In the application.properties Spring Boot configuration file, you have the add your database configuration properties:
spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://localhost:5432/teste
spring.datasource.username = klebermo
spring.datasource.password = 123
Add Hibernate specific properties
And, in the same application.properties configuration file, you can also set custom Hibernate properties:
# Log SQL statements
spring.jpa.show-sql = false
# Hibernate ddl auto for generating the database schema
spring.jpa.hibernate.ddl-auto = create
# Hibernate database Dialect
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
That's it!
I ran into the same problem and my issue was that the DB I was trying to connect to didn't exist.
I created the DB, verified the URL/connection string and reran and everything worked as expected.
I had same issue. adding this to the application.properties solved the issue:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
The following are some of the reasons for the hibernate.dialect not set issue.
Most of these exceptions are shown in the startup log which is finally followed by the mentioned issue.
Example: In Spring boot app with Postgres DB
1. Check if the database is actually installed and its server is started.
org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
java.net.ConnectException: Connection refused: connect
org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
2. Check if the database name is correctly mentioned.
org.postgresql.util.PSQLException: FATAL: database "foo" does not exist
In application.properties file,
spring.datasource.url = jdbc:postgresql://localhost:5432/foo
but foo didn't exist.
So I created the database from pgAdmin for postgres
CREATE DATABASE foo;
3. Check if the host name and server port is accessible.
org.postgresql.util.PSQLException: Connection to localhost:5431 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
java.net.ConnectException: Connection refused: connect
4. Check if the database credentials are correct.
as #Pankaj mentioned
org.postgresql.util.PSQLException: FATAL: password authentication failed for user "postgres"
spring.datasource.username= {DB USERNAME HERE}
spring.datasource.password= {DB PASSWORD HERE}
In spring boot for jpa java config you need to extend JpaBaseConfiguration and implement it's abstract methods.
#Configuration
public class JpaConfig extends JpaBaseConfiguration {
#Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
return vendorAdapter;
}
#Override
protected Map<String, Object> getVendorProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
}
}
this is happening because your code is not bale to connect the database. Make sure you have mysql driver and username, password correct.
Make sure your application.properties has all correct info: (I changed my db port from 8889 to 3306 it worked)
db.url: jdbc:mysql://localhost:3306/test
It turns out there is no one mentioning set spring.jpa.database=mysql in application.properties file, if you use Spring JPA. This is the simplest answer to me and I want to share in this question.
In my case the user could not connect to the database. If will have same issue if the log contains a warning just before the exception:
WARN HHH000342: Could not obtain connection to query metadata : Login failed for user 'my_user'.
Make sure you have your database in your pom like OP did. That was my problem.
My problem was that embedded database was already connected. close connection
I got this issue when Eclipse was unable to find the JDBC driver. Had to do a gradle refresh from the eclipse to get this work.
I had the same issue and after debugging it turns out that Spring application.properties had wrong IP address for DB server
spring.datasource.url=jdbc:oracle:thin:#WRONG:1521/DEV
If you are using this line:
sessionFactory.getHibernateProperties().put("hibernate.dialect", env.getProperty("hibernate.dialect"));
make sure that env.getProperty("hibernate.dialect") is not null.
Same but in a JBoss WildFly AS.
Solved with properties in my META-INF/persistence.xml
<properties>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<property name="spring.jpa.database-platform" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="spring.jpa.show-sql" value="false" />
</properties>
For those working with AWS MySQL RDS, it may occur when you are unable to connect to the database. Go to AWS Security Groups setting for MySQL RDS and edit the inbound IP rule by refreshing MyIP.
I faced this issue and doing above got the problem fixed for me.
I also had this problem. In my case it was because of no grants were assigned to MySQL user. Assigning grants to MySQL user which my app uses resolved the issue:
grant select, insert, delete, update on my_db.* to 'my_user'#'%';
Adding spring.jpa.database-platform=org.hibernate.dialect.MariaDB53Dialect to my properties file worked for me.
PS: i'm using MariaDB
I reproduced this error message in the following three cases:
There does not exist database user with username written in application.properties file or persistence.properties file or, as in your case, in HibernateConfig file
The deployed database has that user but user is identified by different password than that in one of above files
The database has that user and the passwords match but that user does not have all privileges needed to accomplish all database tasks that your spring-boot app does
The obvious solution is to create new database user with the same username and password as in the spring-boot app or change username and password in your spring-boot app files to match an existing database user and grant sufficient privileges to that database user. In case of MySQL database this can be done as shown below:
mysql -u root -p
>CREATE USER 'theuser'#'localhost' IDENTIFIED BY 'thepassword';
>GRANT ALL ON *.* to theuser#localhost IDENTIFIED BY 'thepassword';
>FLUSH PRIVILEGES;
Obviously there are similar commands in Postgresql but I haven't tested if in case of Postgresql this error message can be reproduced in these three cases.
I had the same issue and it was caused by being unable to connect to the database instance. Look for hibernate error HHH000342 in the log above that error, it should give you an idea to where the db connection is failing (incorrect username/pass, url, etc.)
This happened to me because I hadn't added the conf.configure(); before beginning the session:
Configuration conf = new Configuration();
conf.configure();
Make sure that you have enter valid detail in application.properties and whether your database server is available. As a example when you are connecting with MySQL check whether XAMPP is running properly.
I faced the same issue: The db I was trying to connect did not exist. I used jpa.database=default (which I guess means it will try to connect to the database and then auto select the dialect). Once I started the database, it worked fine without any change.
I faced this issue due to Mysql 8.0.11 version reverting back to 5.7 solved for me
I had the same error after using the hibernate code generation
https://www.mkyong.com/hibernate/how-to-generate-code-with-hibernate-tools/
then the hibernate.cfg.xml was created in /src/main/java
but without the connection parameters
after removing it - my problem was solved

Categories

Resources