A double sequence is generated in the Spring Boot app - spring

I'm developing a Spring Boot application and I'm having a problem with sequence generation.
For migrations I use liquibase.
I create a sequence in liquibase.
CREATE SEQUENCE public.additional_services_id_seq
INCREMENT BY 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1
NO CYCLE;
Entity code
#Getter
#MappedSuperclass
public abstract class BaseEntity {
#Id
private Integer id;
}
After running the application and migration, there are
two sequences for the model.
First
-- auto-generated definition
create sequence additional_services_id_seq
maxvalue 2147483647;
alter sequence additional_services_id_seq owner to postgres;
Second
-- auto-generated definition
create sequence additional_services_id_seq1
as integer;
alter sequence additional_services_id_seq1 owner to postgres;
alter sequence additional_services_id_seq1 owned by additional_services.id;
application.yaml settings -
jpa:
show-sql: true
generate-ddl: false
hibernate:
ddl-auto: validate
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.PostgreSQL94Dialect
order_inserts: true
jdbc:
batch_size: 50
open-in-view: false
How do I set up my application so that only the sequences that I created in the migration appear?

Related

H2: always try to create tabes with file database

I have configured the application-local.yml like this to do some tests in local:
spring:
datasource:
url: jdbc:h2:file:./data/db-test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: dbtest
password: dbtest
driver-class-name: org.h2.Driver
jpa:
show-sql: true
generate-ddl: false
properties:
# to prevent this issue : https://stackoverflow.com/questions/4588755/disabling-contextual-lob-creation-as-createclob-method-threw-error
hibernate.temp.use_jdbc_metadata_defaults : false
hibernate:
dialect: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: update
h2:
console:
enabled: true
path: /public/h2-console
liquibase:
enabled: false
The first time the server is started, I see some logs from Hibernate to create tables and the file for the database is created.
The issue is that when I restart the server, I have some errors because it tries to create again the same tables, constraints... I have the ddl-auto set to update so I do not understand why. I tried to update the generate-ddl value to false but it is the same.
Here is an exemple of what I have:
Hibernate: create table myTable (id bigint not null, ..., primary key (id))
15:59:49.252 [restartedMain] WARN o.h.t.s.i.ExceptionHandlerLoggedImpl - GenerationTarget encountered exception accepting command : Error executing DDL "create table myTable (id bigint not null, ..., primary key (id))" via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table myTable(id bigint not null, ..., primary key (id))" via JDBC Statement
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:562)
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:507)
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.createTable(AbstractSchemaMigrator.java:277)
at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:71)
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:207)
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:114)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:184)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:318)
What am I doing wrong please?
The spring.jpa.generate-ddl: true is forcing spring data JPA to recreate the tables. Just set this to false or delete the key as the default is false. This should fix the Problem. Docs

Spring boot hibernate always drop and create index on server startup

Spring boot hibernate always drop and create ALL the indexs on server startup
spring.jpa.hibernate.ddl-auto = update
Hibernate: alter table product_category_1 drop index UKkqfeccp86g07ipixmg25dnfia
Hibernate: alter table product_category_1 add constraint
UKkqfeccp86g07ipixmg25dnfia unique (org_id, pr_ty_id, name)
Hibernate: alter table product_category_2 drop index UKqa7n4ip0gfa4qpg034ba7bkob
Hibernate: alter table product_category_2 add constraint UKqa7n4ip0gfa4qpg034ba7bkob unique (org_id, pr_ca1_id, name)
If your column type is a longtext, the index is not created so hibernate tries to recreate it.
I was experiencing the same thing, where starting my application resulted in my unique constraints being dropped and re-added:
Hibernate: alter table category drop constraint if exists UK_CATEGORY_PARENT_NAME
Hibernate: alter table category add constraint UK_CATEGORY_PARENT_NAME unique (parent_id, name)
After much internet digging and debugging, I found simply adding the following to my application properties no longer caused the constraints to be dropped:
spring.jpa.properties.hibernate.schema_update.unique_constraint_strategy=RECREATE_QUIETLY
As i observe that few of the unique key drop and create again and again with the property
spring.jpa.hibernate.ddl-auto = update
You have to change the uniqueConstraints write inside the #Table annotation and put the uniqness check at column level
Execute the drop and create unique index again and again every time you restart the project
#Table(name = "XXXX",
uniqueConstraints = {#UniqueConstraint(columnNames = { "tempUserId"}) },
)
Resolve by adding the unique=true and column level
#Column(unique = true)
private Long tempUserId;
And delete uniqueConstraints from the #Table annotation
This will resolve the problem

Tests fail to run with H2 database on Micronaut project with Flyway migrations

I've got a unit test suite in a Micronaut 2.0.3 project that's supposed to run on an H2 DB. Since I started using Flyway for my DB migrations, I'm getting an error coming from H2 being unable to run the migrations.
The error is
Bean definition [javax.sql.DataSource] could not be loaded: Migration V1__schema.sql failed
-------------------------------
SQL State : 42001
Error Code : 42001
Message : Syntax error in SQL statement "CREATE DATABASE[*] IF NOT EXISTS MY_DB"; expected "OR, FORCE, VIEW, ALIAS, SEQUENCE, USER, TRIGGER, ROLE, SCHEMA, CONSTANT, DOMAIN, TYPE, DATATYPE, AGGREGATE, LINKED, MEMORY, CACHED, LOCAL, GLOBAL, TEMP, TEMPORARY, TABLE, SYNONYM, PRIMARY, UNIQUE, HASH, SPATIAL, INDEX"; SQL statement:
CREATE DATABASE if not exists my_db [42001-200]
Location : db/migration/V1__schema.sql (/somelocation/build/resources/main/db/migration/V1__schema.sql)
Line : 1
Statement : CREATE DATABASE if not exists my_db
io.micronaut.context.exceptions.BeanInstantiationException: Bean definition [javax.sql.DataSource] could not be loaded: Migration V1__schema.sql failed
-------------------------------
My application.yml is configured to point at a MariaDB instance in Azure like so:
micronaut:
application:
name: myapp
server:
context-path: /myapp/api
cors:
enabled: true
endpoints:
all:
enabled: true
sensitive: false
datasources:
default:
url: jdbc:mariadb://${ENV_DB_HOST_PORT:myurl.mariadb.database.azure.com}:${ENV_DB_PORT:3306}/${ENV_DB_SCHEMA:my_db}?useSSL=${ENV_DB_USE_SSL:true}&useUnicode=true&serverTimezone=Europe/London&autoReconnect=true
driverClassName: org.mariadb.jdbc.Driver
username: myusername
password: mypassword
dialect: MYSQL
allow-pool-suspension: false
connection-test-query: SELECT 1
connection-timeout: 30000
max-lifetime: 60000
maximum-pool-size: 10
minimum-idle: 1
flyway:
datasources:
default:
enabled: true
But my application-test.yml points at the H2 DB for testing purposes:
datasources:
default:
url: jdbc:h2:mem:devDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
driverClassName: org.h2.Driver
username: sa
password: ''
jpa:
default:
properties:
hibernate:
hbm2ddl:
auto: update
And my migration file V1__schema.sql looks like the following:
CREATE DATABASE if not exists my_db;
use my_db;
DROP TABLE IF EXISTS `preset`;
CREATE TABLE `preset` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`preset_name` varchar(30) NOT NULL,
`preset_value` varchar(4000) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `note`;
CREATE TABLE `note` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(30) NOT NULL,
`text` varchar(4000) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The error is pretty much self explanatory
Message : Syntax error in SQL statement "CREATE DATABASE[*] IF NOT EXISTS MY_DB";
CREATE DATABASE if not exists my_db;
According to H2 commands, CREATE DATABASE is not a valid command for H2. You probably need the command CREATE SCHEMA if not exists my_db;

Hibernate Jpa - constraint violation exception on Primary Key(Sequence)

I use Hibernate JPA in my application. I have a Table that has a Primary key(Sequence). Service inserts records to that table.
Version: Oracle 12c
Dialect: org.hibernate.dialect.Oracle10gDialect
Issue :
We face problem(Unique constraint violation on SEQUENCE Key) during the load testing.
Questions :
This issue is not occurring all the time. But only during load test. Can someone please check and help to use thread safe generator?
Is it DB side sequence definition issue or at Java side?
DB Sequence :
CREATE SEQUENCE MY_SEQ
START WITH 1
INCREMENT BY 1
NOMINVALUE
NOMAXVALUE
CACHE 30
NOORDER;
CREATE TABLE MY_TABLE (
MY_PRIMARY_KEY INT default MY_SEQ.nextval NOT NULL,
VALUE_COL VARCHAR2(10) NULL
);
Entity :
public class MyTableEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "MY_PRIMARY_KEY")
#GenericGenerator(
        name = "mySequenceGenerator",
        strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                #Parameter(name = "sequence_name", value = "SEQUENCE MY_SEQ"),
                #Parameter(name = "increment_size", value = "1")
        }
)
#GeneratedValue(generator = "mySequenceGenerator")
private long myPrimaryKey;
#Column(name = "VALUE")
private String value;
}
Oracle 10 Dialect
For Oracle10gDialect use this configuration
#Id
#Column(name = "MY_PRIMARY_KEY")
#GeneratedValue(strategy=GenerationType.AUTO)
Long myPrimaryKey;
Hibernate creates a table and a sequence:
create table MY_TABLE (
MY_PRIMARY_KEY number(19,0) not null,
VALUE varchar2(255 char),
primary key (MY_PRIMARY_KEY))
create sequence hibernate_sequence
While storing it first gets the new sequence ID and than passes it in the INSERT statement
select hibernate_sequence.nextval from dual
insert into MY_TABLE (VALUE, MY_PRIMARY_KEY) values (?, ?)
Oracle 12 Dialect
If you use Oracle 12 that natively supports IDENTITY column it is prefered to upgrade to Oracle12cDialect (note that this requires Hibernate 5.3)
Set the strategy to GenerationType.IDENTITY
#Id
#Column(name = "MY_PRIMARY_KEY", updatable = false, nullable = false)
#GeneratedValue(strategy=GenerationType.IDENTITY)
Long myPrimaryKey;
The following table is created - the important part is generated as identity which provides the unique velues.
Note that no explicite sequence is required to be created, it is managed internally .
create table MY_TABLE (
MY_PRIMARY_KEY number(19,0) generated as identity,
VALUE varchar2(255 char),
primary key (MY_PRIMARY_KEY))
While storing no ID is passed in the INSERT, it is assigned by Oracle and returned to the session
insert into MY_TABLE (VALUE) values (?) RETURNING MY_PRIMARY_KEY INTO ?
Note that in contrary to the Oracle 10 you save one round trip to the database.
Change long to Long
Because if you use long, it (by default) is 0. No generator is allowed to change existing values!
https://docs.oracle.com/javaee/7/api/javax/persistence/GeneratedValue.html

Way to get GORM/Hibernate to work with trigger that sets primary key

I have an existing Oracle database that sets the primary key for an insert via a trigger.
TRIGGER SET_schedtemplate_id_template
BEFORE INSERT
ON schedtemplate
FOR EACH ROW
BEGIN
SELECT schedtemplate_id_template_SEQ.NEXTVAL
INTO :NEW.id_template
FROM DUAL;
END;
We have other applications that depend on this approach for this database
I want to be able to map this database in GORM in my domain object
static mapping = {
autoTimestamp true
table 'schedtemplate'
version false
id column: 'id_template', generator: 'sequence', params: [sequence: 'SCHEDTEMPLATE_ID_TEMPLATE_SEQ']
}
The problem with this approach is that GORM increments the sequence to say 12 but then on insert the sequence gets incremented again to 13. This means other objects in the object graph violate foreign key constraints as they are using GORM's 12 instead of the trigger's 13.
It appears the hibernate setting hibernate.jdbc.use_get_generated_keys = true was developed for this purpose.
How do I configure GORM/Grails to use this setting?
The trigger assigned identity column in Hibernate was discussed here hibernate and DB triggers
Now there is a question, how to configure it in GORM.
Try to use the custom identity generator described above like this :
static mapping = {
...
id column: 'id_template', generator: 'jpl.hibernate.util.TriggerAssignedIdentityGenerator'
}

Resources