Hibernate time to first action - too slow - java

I started a new Java Spring Hibernate project. I only have a few POJO's for now. But hibernate's first actions (drop, create table etc.) happens too late, almost 30 seconds after project gets started.
As I said, there isn't much of a code right now. I'm very new at Java web development and Hibernate. This is my application.properties:
spring.datasource.url=jdbc:oracle:thin:#//localhost:1521/xe
spring.datasource.username=system
spring.datasource.password=*****
spring.datasource.testWhileIdle=true
spring.datasource.validationQuery=SELECT 1
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.naming.physical-strategy=com.bmt311.dershane.CustomPhysicalNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect

Why would you always recreate a database when developing locally? Oracle AFAIK does quite a lot of stuff(reserve diskspace etc.) when using DDL so it is generally a bad idea to use create-drop with Oracle. Try using spring.jpa.hibernate.ddl-auto=update instead for developing locally, or even better, use a dedicated tool for schema management like Liquibase or Flyway and use spring.jpa.hibernate.ddl-auto=none.

Related

Spring boot start up Building JPA container very slow

I am using Spring Boot with JPA and it has recently started to take a long time to start up. It always gets stuck on this line in the console for about 5 minutes:
Building JPA container EntityManagerFactory for persistence unit 'default'
I have seen this related post:
Very slow Spring Boot application startup
And have tried adding spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false to my application.properties
But this made no difference at all.
Is there any way to debug what spring boot is actually doing during this time?
My gradle dependencies are as follows:
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-tomcat')
compile('org.springframework.boot:spring-boot-starter-data-redis')
compile('org.springframework.boot:spring-boot-starter-mail')
compile('org.springframework.session:spring-session:1.3.1.RELEASE')
compile('mysql:mysql-connector-java')
compile('org.apache.commons:commons-lang3:3.7')
compile('com.google.cloud:google-cloud-storage:1.14.0')
compile('javaxt:javaxt-core:1.8.1')
compile('org.hibernate:hibernate-envers:5.0.12.Final')
testCompile('org.springframework.boot:spring-boot-starter-test')
And I am using Spring Boot version 1.5.9.RELEASE
My application.properties has this:
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://notreal.server.com:3306/testdb
spring.datasource.username=NotRealUser
spring.datasource.password=NotRealPwd
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
Any suggestions / help much appreciated.
I managed to fix my problem by setting spring.jpa.hibernate.ddl-auto=none in my application.properties (previously set to auto).
I think this prevents Hibernate trying to compared object models with tables in the database. Springboot start-up was much quicker afterwards.
I should mention that around then we also added Hibernate Envers (auditing framework) to the project which generated a bunch of new tables in the database. So this probably compounded the issue.
Had the same issue within Hashicorp Nomad. Would apply on any system that allocates memory.
If you look at the system logs (not Spring Apps) you will see this step is more memory intensive. Increase memory for the application and it should run with spring.jpa.hibernate.ddl-auto=auto

Spring Boot schema.sql - drop db schema on restart

Hi I'm using Spring Boot version 1.5.9.
When using Spring Boot to initialize schema.sql for mysql database, it works all fine and the database schema is getting created successfully. But on restart of the application this schema.sql script is executing again and the application fails to start because the tables already exist.
I tried spring.jpa.hibernate.ddl-auto=create-drop option in application.properties but it does not have any effect (probably because it only works for Hibernate entities which I'm not using)
Is there a way to have Spring Boot to re-create schema from schema.sql every time on restart if the database is not in-memory one?
GitHub:
https://github.com/itisha/spring-batch-demo/tree/database-input
According to the documentation you can simply ignore exceptions by setting spring.datasource.continue-on-error property to true
Spring Boot enables the fail-fast feature of the Spring JDBC
initializer by default, so if the scripts cause exceptions the
application will fail to start. You can tune that using
spring.datasource.continue-on-error.
or even turn it off with spring.datasource.initialize set to false
You can also disable initialization by setting spring.datasource.initialize to false.
A workaround could be, to change the create statements in your schema.sql
from
CREATE TABLE test .....
to
CREATE TABLE IF NOT EXISTS test ...
use the IF NOT EXISTS statements
turn off automatic schema creation to avoid conflicts: add this line in your application.properties
spring.jpa.hibernate.ddl-auto=none

Spring Auto configuration resulting in old MySQL dialect

I created a small POC app with spring boot, using hibernate (5.2.9) and maria db (10.1.19).
I had some sql dialect issues where my create/drop table SQL was using type=MyIasam but resolved that locally by setting the spring.jpa.properties.hibernate.dialect, however, when I deploy to the cloud (PCF) all of the cloud profile stuff kicks in, and I end up with hibernate deciding its dialect is going to be org.hibernate.dialect.MySQLDialect
this results in invalid SQL getting generated for creating new tables.
Note that I'm not really sure what else could be happening. This is a spring boot app (1.5.3) and the cloud profile is kicking in to do auto configuration. There's a bunch of properties injected. And I can't seem to get my dialect property to be respected.
This is a solid crushingly easy problem that is the escaping me.
Any ideas what I need to set, or provide as dependencies?
I tried removing all of the mysql dependencies, but then the connection string inject is jdbc:mysql... which i think may be part of the problem...

Are batch inserts not working only because of the MySQL driver? What about others?

Earlier I was trying to get batch inserts working in Hibernate. I tried everything: For the config I set batch_size(50), order_inserts(true), order_updates(true), use_second_level_cache(false), use_query_cache(false). For the session I used setCacheMode(CacheMode.IGNORE) and setFlushMode(FlushMode.MANUAL). Still the MySQL query log showed that each insert was coming in separately.
The ONLY thing that worked was setting rewriteBatchedStatements=true in the JBDC connection string. This worries me, as my application is supposed to support any JBDC database and I'm trying to avoid DB specific optimizations.
Is the only reason hibernate can't actually use batch statements because the MySQL driver doesn't support them by default? What about other drivers, do I have to add options to the connection string so they can support batched inserts? If you need specific db's, think SQL server, sqlite, Postgres, etc
One reason it could not be working is that hibernate disables batching if you use the Identity id generation strategy.
Also MySQL doesn't support JDBC batch prepared statements the same way as other databases without turning on the rewrite option.
I don't see that it is a problem to turn this flag on though, if your are setting up your application for a different database you will have to change the settings such as dialect, driver name, etc. anyway and as this is part of the JDBC connect String then you are isolated from the configuration.
Basically I think you are doing the right thing.
As batch insert (or bulk insert) is part of the SQL standard, ORM frameworks like Hibernate support and implement it. Please see Chapter 13. Batch Processing and Hibernate / MySQL Bulk insert problem .
Basically, you need to set the JDBC batch size via the variable named hibernate.jdbc.batch_size to a reasonable size. Also don't forget to end the batch transaction with flush() and clear().

Flyway and JPA integration

My current Spring 3.0 project is integrating with Flyway.
Thanks to the google site so there are document I can counting on. But unfortunately there is not much talking about integration with JPA.
So the questions is:
How to integrate Flyway with persistence.xml? And how does it work? Each time JPA provider will auto generate schema update so how we run a script before or after then?
I guess the query by flyway so far does not support HQL and such so is there any sample code then I can go through to know how to integrate the migration event? Design an interceptor or a new aspect?What to do on a domain level?
Any hint is appreciated. Thanks in advance.
Flyway has no support for JPA and Spring. It basically runs your SQL (not HQL) scripts in order and keeps track of them. And does it well. It remains agnostic to how you use your database and how you produce your upgrade scripts.
However, there's hope. Your persistence provider will most likely support updating existing schema (I know hibernate and eclipselink can), running ALTER and CREATE statements on startup. The migration SQL scripts aren't perfect and it won't always work, but it's a good start. Log these scripts, collect into SQL file, clean-up and use as V_*.sql file supplied to Flyway.
UPDATE: although there is no direct support for spring framework, you can easily integrate it with existing Spring application. This approach is proven to work on production and plays nicely:
<bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate">
<property name="dataSource" ref="..."/>
...
</bean>
Bonus: it works great with Java configuration (with Scala) as well:
#Bean(initMethod = "migrate")
def flyway() = {
val fly = new Flyway()
fly.setDataSource(dataSource)
fly
}

Categories