Recently, i have converted my entities to be portable.
We like that our entities can be use with oracle database and mysql(Before it's only oracle).
Before, to generate an entity id, we use SequenceGenerator and now we have changed to GenericGenerator.
Old code :
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_1")
#SequenceGenerator(name = "SEQ_1", sequenceName = "SEQ_1", allocationSize = 1)
public Long getId() {
return this.id;
}
New code :
#GenericGenerator(name="SEQ_1", strategy="org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters={
#Parameter(name="sequence_name",value="SEQ_1"),
#Parameter(name="optimizer", value="seqhilo"),
#Parameter(name="initial_value",value="1"),
#Parameter(name="increment_size",value="1")
})
public Long getId() {
return this.id;
}
And My problem is that, we have many exception on entities creation when we work on multithreading.
We use 3.3.2 of version Hibernate.
Related
I am using hibernate entity and a sequence generator with it.
Database is Postgres and hibernate version is - 5.4.24.Final.
I have a table X with a sequence "seq_x" and below is the hibernate model for it.
#Audited
#Entity
#Table(name = "x")
public class XModel {
private Long id;
private String strCol;
#Id
#Column(name = "id_gen", columnDefinition = "serial")
#GeneratedValue(strategy= GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "str_col")
public String getStrCol() {
return strCol;
}
public void setStrCol(String strCol) {
this.strCol = strCol;
}
}
Now the problem occurs when inserting a value in table X using hibernate model.
Sometimes the insertion fails as i have not explicitly specified the sequence name "seq_x" using #GenericGenerator and hibernate was looking for a default sequence name "x_id_gen_seq". That seems to be a valid behaviour. In this case i see the below query in logs throwing exception:
select currval('x_id_gen_seq')
Now Sometimes, the insertion works and in logs i see
"2022-06-13 11:44:25,431 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] (default task-116) Natively generated identity: 523"
Now, i am literally confused what could be the reason behind it. I tried going through the hibernate source code but could not find much.
In a Java (Spring Boot + Spring Data JPA) app, use a basic entity and build the inheritance as shown below:
#MappedSuperclass
public abstract class CookBase extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cook_base_gen")
private long id;
// other fields
}
The following entities are inheriting from base entity:
#Entity
#SequenceGenerator(name = "cook_base_gen", sequenceName = "curb_side_id_seq", allocationSize = 1)
public class CurbSide extends CookBase {
public CurbSide(#NotNull UUID groupUuid, #NotNull String name) {
super(groupUuid, name);
}
}
#Entity
#SequenceGenerator(name = "cook_base_gen", sequenceName = "room_id_seq", allocationSize = 1)
public class Room extends CookBase {
public Room(#NotNull UUID groupUuid, #NotNull String name) {
super(groupUuid, name);
}
}
When running the app, I get the following warning on the console:
Duplicate generator name cook_base_gen
Duplicate generator name cook_base_gen
I think there may be a mistake regarding to the configuration of inheritance, but #SequenceGenerator(name = "cook_base_gen", sequenceName = "room_id_seq") seems ok I think. Any idea?
is there a way to perform insertion of an #Id-column value into a non #Id column when entity is being created/updated to avoid double-save-ing?
#Entity
class DummyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "dummy_id_generator")
#SequenceGenerator(name = "dummy_id_generator", sequenceName = "dummy_id_seq")
Long id;
Long rootId;
}
#Repository
class DummyEntityRepo implements JpaRepository<DummyEntity, Long> {}
#Service
class DummyEntityService {
#Autowired
DummyEntityRepo repo;
void save(DummyEntityVO newDummyEntity) {
var newEntity = newDummyEntity.mapToEntity();
// !!! double save here !!!
repo.save(newEntity);
if(newEntity.getRootId() == null) {
newEntity.setRootId(newEntity.getId());
repo.save(newEntity);
}
}
}
What I was thinking was, since #Id is based on a sequence, I can try extracting next value from it and setting it as id and rootId before saving
Long nextId = // get next id somehow
newEntity.setId(newId);
if (newEntity.getRootId()) {
newEntity.setRootId(nextId);
}
repo.save(newEntity);
However:
I don't like perspective of interfering with Hibernate's id acquisition & saving methods
I found package org.springframework.jdbc.support.incrementer but unfortunately there is no sequence based OOB incrementer for my DB so it would require a custom implementation (found something promising here though)
#GeneratorType allows to generate/set values into entity during insertion phase. Suppose your entity looks like this:
#Entity
class DummyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "dummy_id_generator")
#SequenceGenerator(name = "dummy_id_generator", sequenceName = "dummy_id_seq")
Long id;
#GeneratorType(type = RecordIdGenerator.class, when = GenerationTime.INSERT)
Long rootId;
}
And your RecordIdGenerator class looks like:
public class RecordIdGenerator implements ValueGenerator<Long> {
#Override
public Long generateValue(Session session, Object owner) {
return ((DummyEntity)owner).getId();
}
}
Then when you'll insert new record hibernate will generate similar queries:
Hibernate: select nextval ('dummy_id_seq')
Hibernate: insert into dummy (record_id, id) values (?, ?)
and record_id will be equal to id
I need to use an existing sequence of the db to generate the id of this entity:
#Entity
#Table(schema="sistema", name="clientes_consultas")
public class Consulta implements Serializable {
#Id
#SequenceGenerator(schema = "sistema", sequenceName = "clientes_consultas_id_seq",
name = "seq_c", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_c")
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
This is my sequence, and its stored on a schema that is not the postgres default 'public', its called 'sistema':
Unfortunately, theres an stacktrace saying that the sequence dont exists :(
Any clue?
Your sequence owner is "postgres". Maybe you defined different user than postgres in your connection.
I am creating a app with hibernate as ORM tool and annotations are used for configuring JPA metadata. Now, I am facing some issues with ID generator for entities. My entities are.
#MappedSuperclass
public class IdentityEntity {
#Id
#Column(name = "id")
#TableGenerator(name = "id_generator", table = "db_index", pkColumnName = "id", valueColumnName = "manuitemid", pkColumnValue = "id", allocationSize = 1, initialValue=1000)
#GeneratedValue(strategy = GenerationType.TABLE, generator = "id_generator")
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
In this scenario, whenever tis IdentityEntity will be used as parent class for any entity. The Id generator will use the same column name for generating IDs for all entities.
I tries to put id generator on other entities, with different column name. But hibernate returns a error message that the new column name is not found. As below:
ERROR MultipleHiLoPerTableGenerator - could not read or init a hi value
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'menuitemid' in 'field list'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
I want to change this behavior and create a ID generator for every entity separately. What options do I Have?