Liquibase + Postgresql + Spring Jpa : Id auto increment issue - java

I have the following Id description in the entity:
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
Liquibase instruction for generate this id is following :
<column name="id" autoIncrement="true" type="INT">
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_entity"/>
</column>
Also I have liquibase scripts that insert to this table predefined values, e.g.
<insert tableName="entityTable" schemaName="public">
<column name="id">1</column>
<!- other fields-->
</insert>
The problem has appeared when I try to insert a new record without id using Jpa repository.
I got an error with a message like "duplicate id".
So, I understand that jpa(hibernate) doesn't use postgresql sequence for getting a new id value. And I don't want to include the sequence name to the entity's id description. I have hoped that this situation could be resolved by the postgresql itself.
And I wouldn't to use the 'hibernate_sequence'.
So, any idea how I can resolve this issue.
Thank you.

Liquibase's instruction autoIncrement="true" generates serial column for PostgreSQL. For serial column PostgreSQL will create a sequence with a name like tablename_colname_seq. Default column values will be assigned from this sequence.
But when you explicitly insert a value into serial column, it doesn't affect sequence generator, and its next value will not change. So it can generate a duplicate value, which is exactly your case.
To prevent this after you inserted explicit values you need to change the current value of a sequence generator either with ALTER SEQUENCE statement or with setval() function, e.g.:
ALTER SEQUENCE tablename_colname_seq RESTART WITH 42;
SELECT setval('tablename_colname_seq', (SELECT max(colname) FROM tablename));
This should fix the issue.

First create to table name example:
CREATE TABLE TABLE_NAME(ID_NAME SERIAL PRIMARY KEY NOT NULL);
Then in your annotation:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long nameAtribute;

Related

Autoincrement in liquibase

How do i set the autoincrement property using 'startWith' on a column in PostgreSQL using liquibase??
For some reason it always starts from 1. I tried using a custom sequence but that didn't help either.
<column autoIncrement="true" startWith="100" name="id" type="bigint">
That's my current column definition which does not work.
EDIT:
I want to import data from csv using liquibase. I tried the following:
<changeSet author="author" id="createSequence">
<createSequence
incrementBy="1"
sequenceName="mytable_id_seq"
startValue="1000"/>
</changeSet>
</changeSet>
<changeSet author="author" id="1-mytable">
<createTable tableName="mytable">
<column name="id" type="BIGSERIAL" defaultValueComputed="nextval('mytable_id_seq')">
<constraints primaryKey="true" primaryKeyName="mytable_pkey"/>
</column>
</createTable>
<loadData encoding="UTF-8"
file="liquibase/data/mytable.csv"
separator=","
tableName="mytable">
</loadData>
</changeSet>
If i try this I receive the following error 'currval of sequence "table_id_seq" is not yet defined in this session' and I think that it uses the sequence from the public schema instead of what i have set to liquibase.
Another thing i tried was to update it manually:
ALTER SEQUENCE mytable_id_seq restart with 100;
In this case the sequence used was the one from the public schema, but i want to use the schema set to liquibase
Instead of using bigserial which is an autoincrementing bigint specific to postgres use bigint if you are going to be setting up your own increment and sequence.
"The data types smallserial, serial and bigserial are not true types, but merely a notational convenience for creating unique identifier columns (similar to the AUTO_INCREMENT property supported by some other databases). In the current implementation, specifying:"
CREATE TABLE tablename (
colname SERIAL
);
is the same as
CREATE SEQUENCE tablename_colname_seq AS integer;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
From here
https://www.postgresql.org/docs/12/datatype-numeric.html

Alter sequence in H2

I'm using Postgres database in production and H2 for tests.
I want to create a new sequence for an existing table - so in Liquibase I wrote this:
<changeSet id="Add sequence for BOOKS" author="library">
<createSequence sequenceName="BOOKS_SEQ" incrementBy="500" startValue="1"/>
</changeSet>
My Entity looks like this:
#Entity
#Table(name = "BOOKS")
#SequenceGenerator(name = "BOOKS_SEQ", allocationSize = 500)
public class Book {
#Id
#GeneratedValue(generator = "BOOKS_SEQ", strategy = GenerationType.TABLE)
private Long id;
#ManyToOne
#JoinColumn(name = "AUTHOR_ID")
private Author author;
...
}
Now, since I already have entities in this table (with Ids from the last sequence I used), I need to set the current value of this sequence accordingly.
For that matter I wrote:
<changeSet id="Alter sequence for BOOKS" author="library">
<sql dbms="postgresql">select setval('BOOKS_SEQ', (select nextval('OLD_SEQUENCE_UID')))</sql>
</changeSet>
<changeSet id="Add default value to BOOKS.ID" author="library">
<addDefaultValue tableName="BOOKS" columnName="ID" defaultValueSequenceNext="BOOKS_SEQ"/>
</changeSet>
In Postgres (production), it seems to work just fine - but in H2 I get an error message "The sequence named [BOOKS_SEQ] is setup incorrectly. Its increment does not match its pre-allocation size".
According to this - I need to set the start_value (or current value) to something greater than 500 - but I can't figure out how this can be done in H2.
So my question is: How can I set the current value of a sequence in H2?
Have you tried with this?
alter sequence <your_sequence_name> restart with <next_value>
For example:
alter sequence BOOKS_SEQ restart with 500
When I run the above command, I have BOOKS_SEQ set its current value to 499 (so the next value will be 500).

How can i refresh my primary key column?

Till recent time i was using hibernate #Entity annotation to map to database tables.All the primary keys are annotated with #GeneratedValue(strategy = GenerationType.IDENTITY)
I got a scenario where i need to create new schema + migrate data from old schema into new schema.(with few column changes like drop, length and type)
After successful migration of data to new schema tables when i try to insert data using Application its throwing an exception
[ERROR] util.JDBCExceptionReporter DB2 SQL Error: SQLCODE=-803, SQLSTATE=23505, SQLERRMC=1; _NewSchema_._TableName_ , DRIVER=3.51.90
I believe that application is trying to insert rows again with Primary key value starting from 1 because same application is working fine with empty tables.
I want data rows to be inserted with its primary key value as highest value of existing rows primary key .
Any help will be thank full :)
Yes you can do that by altering the table. Alter the table and set starting index for identity column in DB2.
Suppose maximum rows for TBALE_A is 50 and name of identity column is TABLE_ID
ALTER TABLE TBALE_A ALTER COLUMN TABLE_ID
RESTART WITH 51
Your guess is correct, here is my solution, execute the following SQL to give the ID column a specified start position, then your application will work fine.
alter table TABLE_NAME alter column ID set GENERATED BY DEFAULT RESTART WITH 10000;
Hope to help you :)
In case of generation type , IDENTITY, you should look for identity column to be auto incemental.
#GeneratedValue(strategy = GenerationType.IDENTITY) required primary key column to be auto incremental.

Hibernate Identity column but not primary key

I have one sqlserver 2008 r2 datatable, it has one column autoId int identity(1,1), but it's not the primary key, another column varchar(20) is the one.
question is : how do i config the hbm file?
bellow is my config file,but it got errors when i try to save one instance.
"Cannot insert explicit value for identity column in table 'acct_info' when IDENTITY_INSERT is set to OFF."
<property name="autoId" type="int">
<column name="auto_id" not-null="true" unique="true" />
</property>
There can be two reasons , either you don't have sufficient privileges in DB for IDENTITY INSERT or there is mismatch in the mechanism by which you are trying to set an identifier in hibernate and DB layer.
You can have a look at your id generation strategy in hibernate definition file
In DB you can change to Set IDENTITY_INSERT to "ON"
Pick a different generator class

Java Hibernate id auto increment

Hy
I'v a little problem with hibernate on netbeans.
I've a table with an Auto increment id :
CREATE TABLE "DVD"
(
"DVD_ID" INT not null primary key
GENERATED ALWAYS AS IDENTITY
(START WITH 1, INCREMENT BY 1),
"TITLE" VARCHAR(150),
"COM" LONG VARCHAR,
"COVER" VARCHAR(150)
);
But this auto increment is not properly detected with Reverse Engineering.
I get a map file with this :
<id name="dvdId" type="int">
<column name="DVD_ID" />
<generator class="assigned" />
</id>
i've looked on google and on this site ... foud some stuf but i'm still stuck..
i've tried to add insert="false" update="false" on the map file but i get back :
Caused by: org.xml.sax.SAXParseException: Attribute "insert" must be declared for element type "id".
Anny help will be pleased
Vincent
Change the generator class to "identity" if you want an auto-generated value from the database.
I'm not sure if I got you well but if you aren't using user input for "id" and you want it to autogenerate and autoincrement, then just change class="assigned" to class="increment".

Categories

Resources