I'm building a small spring-boot application. I'm using spring-data-jpa to create the database schema and liquibase to populate it with test data.
application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/book-db
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=admin
spring.datasource.password=lTIDDYz3n3jD3BeYaAJz
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
According to the documentation no configuration for liquibase is required if I have a gradle dependency and master changeLog under the default path.
db.changelog-master.yaml:
databaseChangeLog:
- changeSet:
id: 1
author: jb
changes:
- sqlFile:
path: db/migration/insert-books.sql
insert-books.sql:
--liquibase formatted sql
--changeset admin:1
delete from book;
insert into book (id, title)
values (nextval('seq'), 'Functional Programming for Mortals');
commit;
I have tried it with and without commit. The tables databasechangelog and databasechangelog are created successfully and contain the migration (insert-books).
The migration goes through, because if I add an invalid insert (to some table that does not exist), I get the exception:
ERROR: relation "xxx" does not exist
How to populate the database with data in insert-books.sql script using liquibase?
Don't use both, liquibase and JPA, to manage the DB structure. If you want to use liquibase, set JPA (Hibernate) to just validate the schema and manage the schema within liquibase.
spring.jpa.hibernate.ddl-auto=validate
The problem with your solution is in the order of operations. When your application starts, it first runs liquibase, which inserts the data, then JPA is started and the schema is created from scratch.
Try dropping the schema before running the app, I bet the migration (liquibase) will fail.
Liquibase has to be in charge of the schema, there is a way to add liquibase to an existing database, but it again makes liquibase the owner of the schema:
Using liquibase on the existing database
Related
I use Hibernate in my Spring Boot app and populate the tables without any problem. However, I am trying to add 2 record to one of the populated table using import.sql on the classpath.
INSERT INTO role(id, role_type) VALUES(1, 'ADMIN');
INSERT INTO role(id, role_type) VALUES(2, 'USER');
I also set the following properties:
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.defer-datasource-initialization=true
spring.sql.init.mode=always
When I run the app, tables are created and the data is populated, and tables are created. However, I got "Error executing DDL : alter table user_role drop foreign key" error.
When I update spring.jpa.hibernate.ddl-auto as shown below, there is no error and tables are created. BUT, records are not inserted to the role table:
spring.jpa.hibernate.ddl-auto= update
So, how can I insert data when I run the app without any problem?
import.sql will only be executed provided that spring.jpa.hibernate.ddl-auto is set to create or create-drop.
Alternatively you can use data.sql it will be executed irrespective of hibernate.ddl configuration.
Using spring.jpa.hibernate.ddl-auto= update and data.sql should solve both of your error.
spring.sql.init.mode=always
spring.jpa.defer-datasource-initialization=true
spring.jpa.hibernate.ddl-auto= update
Use defer-datasource
I have all my liquibase changelogs with respect to MySQL database now we are planning to move to MSSQL so when I try to run the existing changelogs which is working fine for MySQL is failing for MSSQL. Is there any configuration in liquibase to handle database migration?
getting below error when I run changelogs on MSSQL
addAfterColumn is not allowed on mssql
you can use dbms attribute and configure changelogs to be executed only on given databases.
I've updated the version of H2 database (used only for testing) from 1.4.196 to 2.1.210 and the migration scripts now fails due to syntax errors.
Migration scripts are 2 types - pre (pure SQL) and post liquibase (XML based) introduction to the project.
Here is what is defiend in the test yaml config:
spring:
datasource:
url: jdbc:h2:mem:testdb;Mode=Oracle
platform: h2 // changed to sql.init.platform: h2
jpa:
hibernate:
ddl-auto: validate
I've tryed to add spring.datasource.driverClassName=org.h2.Driver and spring.jpa.database-platform=org.hibernate.dialect.H2Dialect proerpties, but that did not do the trick.
I very mych tink it is due to some configuration difference between the two version 1.4 and 2.1
COMMENT REPLY
The liquibase changeset that causes the error:
<changeSet id="20191112130000-1" author="zdravko">
<dropColumn tableName="NEWS_CONTENT" columnName="DAY"/>
</changeSet>
Error itself:
Reason: liquibase.exception.DatabaseException: Syntax error in SQL statement "ALTER TABLE PUBLIC.NEWS_CONTENT DROP COLUMN [*]DAY"; expected "identifier"; SQL statement:
ALTER TABLE PUBLIC.NEWS_CONTENT DROP COLUMN DAY [42001-210] [Failed SQL: (42001) ALTER TABLE PUBLIC.NEWS_CONTENT DROP COLUMN DAY]
DAY is a keyword in H2 and it is also a reserved word in the SQL Standard (even in completely outdated SQL-92 and in all newer versions), it means it cannot be used as unquoted identifier.
Liquibase supports H2 2.x.y and its keywords since the version 4.7.0, if you use some older version, you need to upgrade. If you use this or newer version, something is going wrong.
In that case you can check objectQuotingStrategy and use QUOTE_ALL_OBJECTS:
https://docs.liquibase.com/commands/config-ref/objectquotingstrategy.html
Also you can add ;NON_KEYWORDS=DAY to JDBC URL of H2, but it would be better to avoid it if you can, this setting isn't very reliable and should be used only when you can't do anything else.
I am a newbie that only knows basics of Java Core. I have test task where I need to create simple REST Web Service with Spring Boot.
I wrote all the logic in Java Core, and now I try to wrap it in all these technologies.
I am using this guide:
https://spring.io/guides/tutorials/rest/
Here they have JPA entities and #Table annotation, where table name is specified, but there are no SQL scripts to create tables in this guide.
So I thought JPA will create database and tables for entities by itself, but when I uncomment #Table annotation it says "Cannot resolve table '<table_name>'"
I am using IntelliJ IDEA with Spring Boot Maven project with imported Spring Web, H2 and JPA (like the guide tells to do).
I also configured H2 Data Source and tested the connection: works fine. There is a schema, but no tables.
Here is my application.properties:
spring.h2.console.enabled=true
spring.h2.console.path=/h2_console
spring.datasource.url=jdbc:h2:~/kaylemains
spring.datasource.platform=h2
spring.datasource.initialization-mode=always
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.generate-ddl=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
As in the guide, I add entities in LoadDatabase class like this:
#Bean
CommandLineRunner initTournaments(TournamentRepository repository) {
return args -> {
log.info("Preloading " + repository.save(new Tournament("Kayle Mains Competition: Summoner's Gorge", 16)));
};
}
So my question is: can I have file-stored H2 database and do everything with the it (including table creation) from my Java code?
OR it is necessary to create tables manually (by writing SQL scripts with CREATE TABLE) and construct them so that all entities work fine? (that means defining foreign key columns etc.), and only after that will JPA be able to work with this database? Do I need to add #Column annotation to every field, and JPA won't do it by itself for its Entities?
Why am I getting this error of "Cannot resolve table"? Of course it cannot be resolved because it does not exist yet, I thought JPA & Hibernate will create it for me based on entity classes...
Here in Baeldung you have all the information about the properties to ddl generation
Spring provides a JPA-specific property which Hibernate uses for DDL generation: spring.jpa.hibernate.ddl-auto.
create – Hibernate first drops existing tables, then creates new tables
update – the object model created based on the mappings (annotations or XML) >is compared with the existing schema, and then Hibernate updates the schema >according to the diff. It never deletes the existing tables or columns even if >they are no more required by the application
create-drop – similar to create, with the addition that Hibernate will drop >the database after all operations are completed. Typically used for unit testing
validate – Hibernate only validates whether the tables and columns exist, otherwise it throws an exception
none – this value effectively turns off the DDL generation
We have to set the value carefully or use one of the other mechanisms
to initialize the database.
If the problem is still present go to Settings -> Inspections, and uncheck the option "Unresolved database references in annotation"
My question is simple. How to run any DDL statements after Spring's automatic schema creation?
I have set the following in my application-test.properties to auto create the database schema from the entity Java classes.
spring.jpa.hibernate.ddl-auto=create-drop
I'd like to change the data type of one column in one table after the schema is auto created.
I tried having a schema.sql file in the classpath, but that didn't help.
Any help please.
Scripts which you specify in script will run before it create database.
So when you fire Alter table command, you will get Table not found kind of error.
What I would suggest is to create database via SQL file only and set
spring.jpa.hibernate.ddl-auto=none so system wont create auto database.
Now to make your SQL file run, You can create the schema and initialize it based on the platform. Platform value is of spring.datasource.platform. Now you can create files schema-${platform}.sql and data-${platform}.sql which is processed by Spring Boot. It allows you to choose the database specific scripts if necessary. You can choose the vendor name of database(platform) like hsqldb, h2, oracle, mysql, postgresql, and so on.
I have tested with postgres and It worked for me. Sql file name was schema-postgres.sql
Set below properties in application.properties file
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/poc
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=none
spring.datasource.initialization-mode=always