Hibernate duplicate entry for key 'PRIMARY' - java

I want to insert in data base using hibernate in different processes, I get this exception
Duplicate entry '58576' for key 'PRIMARY'
My Generation strategy was Generator.Table.
I changed it to Generator.identity, but get the exception
field dbid doesn't have default value
How can I solve this problem?
my Entity:
#Id
#TableGenerator(name="dbidn",table="dbidpktn",pkColumnName="dbkeyn",
pkColumnValue="dbvaluen",allocationSize=1)
#GeneratedValue(strategy = GenerationType.TABLE, generator = "dbidn")
private Long dbid;

If you would like to use DB dependent IDs try
#GeneratedValue(strategy = GenerationType.AUTO)
And set the primary key field filling on DB level

#Id
#GenericGenerator(name = "announcement", strategy = "increment")
#GeneratedValue(generator = "announcement")
private Integer announcementId;
use GenericGenerator

Related

JPA allocation Size causing Auto Generated Sequence to Reused after AllocationSize

I have recursive parent and child relation for Graph. When I have a large Graph with 50 or more nodes on a Single hibernate session, I get an error message "A different object with the same identifier value was already associated with the session". This is due to the fact the default allocation Size in Spring JPA is 50. I have overcome this error by setting allocationSize to 100 and increment by 100. But that does not solve the root of the problem. I can have any arbitrary # nodes in ONE session. I use saveAndFlush(NodeEntity) which throws this error message.
My question is How do I force Hibernate to fetch the primary key from DB after allocation size is limit is reached and be able to generate a new set primary key in a single session?
Hibernate version: hibernate-core-5.4.30.Final.jar
Error:
A different object with the same identifier value was already associated with the session : [graph.entity.NodeEntity#53]; nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [graph.entity.NodeEntity#53]
//GRAPH DATABASE.
CREATE TABLE IF NOT EXISTS node
(
id SERIAL NOT NULL,
name character varying(255) NOT NULL,
parent_id int,
CONSTRAINT node_pkey PRIMARY KEY (id),
CONSTRAINT node_parent_id_fk FOREIGN KEY (parent_id)
REFERENCES node (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
CREATE TABLE IF NOT EXISTS graph
(
id SERIAL NOT NULL,
name character varying(255) NOT NULL,
node_id int,
CONSTRAINT graph_pkey PRIMARY KEY (id),
CONSTRAINT graph_node_fk FOREIGN KEY (node_id)
REFERENCES node (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT graph_node_id_uk UNIQUE (node_id)
);
public class NodeEntity {
#Id
#SequenceGenerator(name = "node_id_seq", sequenceName = "node_id_seq",allocationSize = 50)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "node_id_seq")
#Column(name = "id")
int id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,orphanRemoval=true)
#JoinColumn(name = "parent_id")
private List<NodeEntity> children = new LinkedList<NodeEntity>();
}
public class GraphEntity{
#Id
#SequenceGenerator(name = "graph_id_seq", sequenceName = "graph_id_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "graph_id_seq")
#Column(name = "id")
int id;
#OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "NODE_ID", unique = true, nullable = true, insertable = true, updatable = true)
private NodeEntity rootNode;
}
// Way to reproduce this.
void generate150deepChild(int count,NodeEntity node){
if(count == 100){
return
}else{
NodeEntity newNode = new NodeEntity("Child " +count)
node.getChildren().add(newNode);
cout++;
generate150deepChild(count,newNode);
}
}
NodeEntity rootNode = new NodeEntity("ROOT");
// PLEASE NOT if # NodeEntity < 50 everything works fine.
generate150deepChild(0,rootNode);
// PLEASE NOT all ids are zero so they are new node.
GraphEntity graph = new GraphEntity("TEST");
graph.setRootNode(rootNode);
graphRepository.saveAndFlush(graph);
// THIS WILL GENERATE Duplicate Primary key for NodeEntity.
Actual stack trace:
Caused by: javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [graph.entity.NodeEntity#131605]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:123)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:823)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:786)
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:261)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:499)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:423)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:220)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:532)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:463)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:426)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:220)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:459)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:247)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:175)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:104)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:813)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:786)
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:261)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:499)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:423)
Change to use GenerationType.SEQUENCE strategy and it should handle for you automatically :
#Id
#SequenceGenerator(name = "node_id_seq", sequenceName = "node_id_seq",allocationSize = 50)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "node_id_seq")
#Column(name = "id")
int id;
And you just need to make sure the followings:
Do not set the ID for each node manually.
The related sequence in DB (i.e. the sequence specified in sequenceName in #SequenceGenerator) is really configured and aligned with what you configure in #SequenceGenerator. In case of PostgreSQL , you can do :
alter sequence node_id_seq increment by 50;
Tip:
According to this, you can change to use the pooled or pooled-lo algorithm to reduce the DB roundtrip to get the ID by configuring the following settings:
<property name="hibernate.id.optimizer.pooled.preferred" value="pooled-lo" />

Spring Boot #GeneratedValue(strategy = GenerationType.IDENTITY) not working

I have created an Entity Student and having following properties:
#Entity
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long studentId;
private String studentName;
// Setters and getters
}
It is generating the studentId like 1,2,3 and so on,that means it is incrementing the value as expected.
Now i have dropped my database student_db and created once again with same name. And then restart my application.Now few things i noticed here:
Its created a student table in my database(As expected).
Then using REST API have created an one entry. (That is created
perfectly)
Now the issue or i don't know what it is ?
I auto generated the studentId from where it is was on last time, i mean studentId is 4. I don't know why it is happening. My expected result is studentId should start from 1 does not matter how many time i dropped my database. This is happening both with #GeneratedValue(strategy = GenerationType.IDENTITY) and #GeneratedValue(strategy = GenerationType.AUTO)
I am using following:
Spring Boot 2.0.0 RELEASE
MySQL 5.7.23
In my application.properties file i have setted
spring.jpa.hibernate.ddl-auto = update
What i am missing here?
This is related with the MySQL itself.
You can try to truncate the table to see if this problem goes away:
TRUNCATE TABLE table_name;
And run the command after to reset the AUTO_INCREMENT:
ALTER TABLE table_name AUTO_INCREMENT = 1;
please try
#GeneratedValue(
strategy= GenerationType.AUTO,
generator="native"
)
#GenericGenerator(
name = "native",
strategy = "native"
)
private Long id;

Hibernate ignores initialValue for sequence generator

I need to have a unique ID across all tables in my database that is starting with an offset, let's say 1000. The IDs below that offset are reserved for special records that are referenced by constants in the Java code. In other words, the first record that is persisted in any table I would expect to have ID 1000, the next one 1001 etc.
I followed the instructions in the Hibernate documentation and various posts and these are the annotations I'm using:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "my_sequence", initialValue = 1000, allocationSize = 10)
private long id;
Unfortunately Hibernate completely ignores the initialValue setting. It generates the following SQL code:
create table hibernate_sequence (next_val bigint)
insert into hibernate_sequence values ( 1 )
I also had a try with the TABLE strategy which also does not work. The ID starts with 1.
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#TableGenerator(name = "my_sequence", initialValue = 1000, allocationSize = 10)
private long id;
By the way, this does work with EclipseLink JPA provider. My Hibernate version is 5.2.7 and I am going through the JPA API. I am using MySQL.
Has anybody experienced this problem?
Thanks in advance.
The generator name must be included in the #GeneratedValue annotation, such as:
#GeneratedValue(strategy = GenerationType.TABLE, generator = "my_sequence")
#TableGenerator(
name = "my_sequence",
table = "id_gen",
pkColumnName = "gen_name",
valueColumnName = "gen_val",
initialValue = 1000,
allocationSize = 10)
I think you have missed some attributes on both of the strategies:
Sequence
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "my_sequence", sequenceName= "dbsequence"
initialValue = 1000, allocationSize = 10)
private long id;
Table
Id generation table should have two columns. The first column is a String type used to identify the particular generator sequence. It is the primary key for all the generators in the table. The Second column is an integer type that stores the actual id sequence that is being generated. The value stored in this column is the last identifier that was allocated in the sequence.
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#TableGenerator(name = "my_sequence"
, table = "id_gen"
, pkColumnName = "gen_name"
, valueColumnName = "gen_val"
, initialValue = 1000, allocationSize = 10)
private long id;
The table strategy is obviously more portable so consider that when you will make a choice.
you should name your #sequencegenerator then add the same name to #generatedvalue
you need also to create-drop your table (in application.properties) or your application is going to run the table with old sequence parameters
`#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE , name="my_sequence")
#SequenceGenerator(name = "my_sequence",sequenceName="my_sequence", initialValue = 1000,allocationSize = 10)
private long id;`

UUID without slashes + Hibernate + MySQL

I save UUID without slashes as varbinary(16) in MySql. I will like to use annotation to map this field in Hibernate. Am I able to do it? Please help.
Here is my mapping:
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "PRODUCT_ID", unique = true)
private String productId;
Here is my insert:
INSERT INTO `item`
(`ID`,
`TITLE`)
VALUES
(
UNHEX('f4e01440cfd011e39c1a0800200c9a66'),
'Apple'
);
But id become something like ��%14#��%11��%1A%08%00 %0C�f in my code.

Auto Increment in hibernate using oracle

I am new to hibernate and I want to insert primary number in my table for unique identification. I am using Oracle as my database so do I need to create sequence in oracle to get auto increment generation number ?
I am using below code but it is not working. I have not created any sequence yet.
#Id
#Column(name = "id" )
#GeneratedValue ( strategy = GenerationType.TABLE)
I have used AUTO, SEQUENCE and IDENTITY but nothing works for me.
this is one way of using Oracle sequence in a JPA mapped entity:
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_NAME")
#SequenceGenerator(name = "SEQUENCE_NAME", sequenceName = "SEQUENCE_NAME", allocationSize = 1, initialValue = 1)
In this way your persist() method will ask for the next value of the sequence in order to use it as ID for your entry.
You can ue this #GeneratedValue(strategy=GenerationType.AUTO)
#Id
#Column(name = "id" )
#GeneratedValue(strategy=GenerationType.AUTO)
In GenerationType.TABLE option, ID value will be filled with the column of other table.
If you are using strategy=GenerationType.TABLE you will require to mention the Table from where your ID will be filled.
For example,
#GeneratedValue(strategy=GenerationType.TABLE, generator="course")
#TableGenerator(
name="course",
table="GENERATOR_TABLE",
pkColumnName = "key",
valueColumnName = "next",
pkColumnValue="course",
allocationSize=30
)
And for other option, you can use GenerationType.AUTO option, and let hibernate decide which option to choose according to databse.
#Id
#Column(name = "id" )
#GeneratedValue (strategy = GenerationType.AUTO)
And make sure that you properly configured hibernate.cfg.xml file.

Categories

Resources