How to create a table using the data.sql file using spring? - spring

My goal is to create a database using a file, but the application does not respond to it, and if I try to add something to the database, I get an error:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "BILLIONAIRE" don't found
And of course the table was not created
application.yml
spring:
datasource:
url: jdbc:h2:mem:test
driverClassName: org.h2.Driver
username: sa
password:
jpa:
database-platform: org.hibernate.dialect.H2Dialect
defer-datasource-initialization: true
hibernate:
ddl-auto: none
data.sql
DROP TABLE IF EXISTS billionaires;
CREATE TABLE billionaires (
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(250) NOT NULL,
last_name VARCHAR(250) NOT NULL,
career VARCHAR(250) DEFAULT NULL
);
INSERT INTO billionaires (first_name, last_name, career) VALUES
('Aliko', 'Dangote', 'Billionaire Industrialist'),
('Bill', 'Gates', 'Billionaire Tech Entrepreneur'),
('Folrunsho', 'Alakija', 'Billionaire Oil Magnate');
model
#Data
#Entity
public class Billionaire {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String first_name;
private String last_name;
private String career;
}
Working version
spring:
sql:
init:
mode: always
datasource:
url: jdbc:h2:mem:test
driverClassName: org.h2.Driver
username: sa
password:
jpa:
database-platform: org.hibernate.dialect.H2Dialect
defer-datasource-initialization: true
hibernate:
ddl-auto: none

Hibernate
In addition, a file named import.sql in the root of the classpath is
executed on startup if Hibernate creates the schema from scratch (that
is, if the ddl-auto property is set to create or create-drop). This
can be useful for demos and for testing if you are careful but is
probably not something you want to be on the classpath in production.
It is a Hibernate feature (and has nothing to do with Spring).
Here you need to change ddl-auto property to create or create-drop (then you can delete CREATE TABLE command from .sql file
Basic SQL script
Spring Boot can automatically create the schema (DDL scripts) of your
JDBC DataSource or R2DBC ConnectionFactory and initialize it (DML
scripts). It loads SQL from the standard root classpath locations:
schema.sql and data.sql, respectively. In addition, Spring Boot
processes the schema-${platform}.sql and data-${platform}.sql files
(if present), where platform is the value of spring.sql.init.platform.
This allows you to switch to database-specific scripts if necessary.
For example, you might choose to set it to the vendor name of the
database (hsqldb, h2, oracle, mysql, postgresql, and so on). By
default, SQL database initialization is only performed when using an
embedded in-memory database. To always initialize an SQL database,
irrespective of its type, set spring.sql.init.mode to always.
Similarly, to disable initialization, set spring.sql.init.mode to
never. By default, Spring Boot enables the fail-fast feature of its
script-based database initializer. This means that, if the scripts
cause exceptions, the application fails to start. You can tune that
behavior by setting spring.sql.init.continue-on-error
Here basically you need to add spring.sql.init.platform=h2 to your properties
Many different approaches are listed here:
Data initialization

Place your data.sql under src/main/resource of your project workspace
And Restart your spring application.

Related

Spring Boot Flyway migration placeholder

Can someone show the right format to use to use application.properties config in Flyway migrations.
I'd like to use the username for the datasource config in my application.properties file to grant permissions on a database table (db migration using Flyway, username will ultimately vary between environments), however I can't find an example of the syntax.
Example application.properties:
# Database
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/example_db
spring.datasource.username=example_db_application
spring.datasource.password=examplePassword1
Migration:
CREATE TABLE token
(
id TEXT,
value TEXT,
);
GRANT SELECT, INSERT, UPDATE, DELETE ON token TO ${spring.datasource.username};
I've tried various iterations (flyway.placeholders.spring.datasource.username, tried specifying no prefix: spring.flyway.placeholder-prefix=) but no luck.
Spring-Boot provides a common application-property for flyway migration placeholder-values under the path spring.flyway.placeholders.*=
Usage
# application.properties
# -> placeholder value `user`
spring.flyway.placeholders.user=joe
-- db/migration/V3__Migration_With_Placeholder.sql`:
CREATE TABLE ${user} (
...
)

H2 error or renaming table from PascalCase to snake_case

I use spring boot in a project. I have liquibase scripts to create tables and enter seed data. The repo tests are run using the #DataJpaTest annotation which by default uses an in-memory h2 database.
The db for this project was initially SQLServer, so the liquibase scripts had table names in PascalCase e.g. FooBar. Later the db had to be changed to PostgreSQL, so new liquibase scripts were added to rename to tables from PascalCase to snake_case e.g. from FooBar to foo_bar.
The liquibase scripts run successfully against the PostgreSQL database, but when they run as part of the repo tests (against the H2 db), the rename scripts fail. They fail when trying to rename a table name with a single word e.g. from Insitution to institution. I get the below error:
Caused by: org.h2.jdbc.JdbcSQLException: Table "INSTITUTION" already exists; SQL statement:
ALTER TABLE PUBLIC.Institution RENAME TO institution [42101-196]
Solution that I have already tried and failed:
A separate application.properties file in src/test/resources pointing to a custom in-memory h2 database which looks as follows:
spring.datasource.url = jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL
spring.datasource.username = sa
spring.datasource.password = sa
spring.datasource.driverClassName = org.h2.Driver
I have also tried to mention the table name in double quotes in the liquibase script thinking it would preserve the case. Did not work
Please help! :(
H2 converts your unquoted table name references to uppercase. If you quote the target name with double quotes:
ALTER TABLE Institution RENAME TO "institution"
... will rename the INSTITUTION table to institution.
Your JPA implementation may have to be configured to quote the table names from here on. With hibernate you can use hibernate.globally_quoted_identifiers=true for that.

Spring boot not creating schema correctly?

I have very simple spring boot app which is using h2 database on local. I have schema-h2.sql which has below script -
CREATE TABLE USERS(
userid NUMBER(10,0) AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(256) UNIQUE NOT NULL,
fname VARCHAR(256),
lname VARCHAR(256)
);
And in application-default.properties -
spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MSSQLServer;DB_CLOSE_DELAY=-1;DB_CLO SE_ON_EXIT=false
When I look at /h2-console, I can see table being created but it is missing unique constraint on email column.
I even tried adding alter statement in schema-h2.sql script to create constraint but that doesn't work either -
ALTER TABLE USERS ADD CONSTRAINT UQ_EMAIL UNIQUE(email);
Also, when run those script in h2-console it creates unique constraint correctly so it does seem like something to do with how spring executes them.
When debugging I can see that Alter statement gets executed without any exception in ScriptUtils class.
Not sure how to take this forward so any help will be greatly appreciated.
For anyone else coming across this, I was able to fix it by altering my JPA annotation. Adding the unique parameter in addition to creating the constraint in h2-schema.sql allowed the constraint to actually be created.
#Column(name = "email", unique = true, nullable = false)
private String email;
If schema is beign created by spring boot with schema.sql file, make sure to disable hibernate schema auto create:
spring.jpa.hibernate.ddl-auto=none
Otherwise, Hibernate will overwritte it everytime the app starts.

How to change the schema name using liquibase

I am using embedded database H2 which has default schema PUBLIC.
I want to have a schema XYZ as opposed to the default H2 schema. How can I change it using liquibase. I tried to create the very first changeset to create schema XYZ and added schemaName attribute to all the DDL statements henceforth to use the schemaName. But databasechangelog and databasechangeloglock are created in PUBLIC schema. How can specify the schema for those tables as well ?
Thank you in advance for your response.
Used INIT=CREATE SCHEMA IF NOT EXISTS TEST and specify 'defaultSchema' attribute to the 'schemaName' in the liquibase bean.

How to cascade deletions with Doctrine 1.2?

I have been struggling with defining cascade behavior in Doctrine ORM.
According to the documentation, one is supposed to use onDelete: CASCADE for database-level cascade (which is what I am trying to achieve here).
A complete example may be seen on the Symfony tutorial.
However, all such cascade specifications are ignored in my schema.
Here is the relevant excerpt:
Advancement:
columns:
association_id:
type: integer(4)
notnull: true
task_id:
type: integer(4)
notnull: true
state:
type: enum
values: ['todo', 'current', 'done', 'cancelled']
notnull: true
relations:
Association:
class: Association
local: association_id
foreignType: one
onDelete: CASCADE
Task:
class: Task
local: task_id
foreignType: one
onDelete: CASCADE
Of course, the Task and Association tables are defined correctly. I won't post them here in the first place to avoid a too long question, but please ask if that seems necessary.
Here is the generated SQL (linebreaks mine):
CREATE TABLE advancement
(id INTEGER PRIMARY KEY AUTOINCREMENT,
association_id INTEGER NOT NULL,
task_id INTEGER NOT NULL,
state VARCHAR(255) NOT NULL);
Not a trace of a CASCADE (nor a REFERENCES, by the way…). Of course, cascading does not work, and I had to implement it manually by altering the default backend actions.
Does anyone know what I am doing wrong here?
I think doctrine will shut up about the fact that your RDBMS (is it MySQL?) does not support cascades if it doesn't. This is the case if you use MySQL with the MyISAM storage engine (which does not support REFERENCES either, by the way...). If I were you, I'd try to create a cascade directly with your RDBMS client, just to check whether it is possible or not.

Resources