Existing sequence Postgres with JPA 2.1 and Spring 4.3 - spring

I am configuring a database pointing entity that already exists
#Id
#SequenceGenerator(name = "contacto_generator", sequenceName = "commons.contacto_sequence")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "contacto_generator")
private Long id;
I have the annotations as I was in the old application.
When I upgrade an entity is fine, but when I create a new entity, the sequence does not work well
The sequence "commons.contacto_sequence" is in the 509.
I even activated "show_sql" and run:
select nextval ('commons.contacto_sequence')
If I run it directly in the database, it goes perfectly
Caused by: org.postgresql.util.PSQLException: ERROR: llave duplicada viola restricción de unicidad «pk_contacto»
Detail: Ya existe la llave (id)=(459).
I do not know where the 459 value is, and no sequence in my database has that value
If you look at the console the name of the sequence appears with rare characters
I do not know what it can be or should change, because in theory is something that should automatically do Spring.
If it is because the annotations are deprecated and does not connect well to the sequence or that can be.
This project has Jpa 2.1, Spring 4.3.x

Try use GenerationType.SEQUENCE strategy:
#Id
#SequenceGenerator(name = "contacto_generator", sequenceName = "commons.contacto_sequence")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "contacto_generator")
private Long id;

Related

Spring Boot Hibernate not picking up use-new-id-generator-mappings property

I'm upgrading my project to Spring Boot 2.1.18 that uses Hibernate 5.3.18.
Previously, my entity looked like thus and would use the SequenceHiLoGenerator:
#Entity
#Table(name = "group_link")
#SequenceGenerator(name = "group_link_seq", sequenceName = "group_link_seq")
public class GroupLinkEntity extends BaseObject {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "group_link_seq")
#Column(name = "group_link_id", unique = true, nullable = false)
private Long id
}
Now, by default in Hibernate 5, it uses the SequenceStyleGenerator which causes constraint violations because my increment size is 1 and the default allocationSize is 50.
The suggested thing to do to maintain compatibility is to set this property:
spring.jpa.properties.hibernate.use-new-id-generator-mappings: false
I do so but it does not seem to take, because the SequenceStyleGenerator is still used. From my understanding, this should cause it to use the SequenceHiLoGenerator. Is this incorrect?
However, if I modify the entity to look like the below it works as expected, replicating the previous functionality I had.
#Entity
#Table(name = "group_link")
#GenericGenerator(
name = "group_link_seq",
strategy = "org.hibernate.id.SequenceHiLoGenerator",
parameters = {
#Parameter(name = "sequence_name", value = "group_link_seq"),
}
)
public class GroupLinkEntity extends BaseObject {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "group_link_seq")
#Column(name = "group_link_id", unique = true, nullable = false)
private Long id;
}
So, it would seem the property is not being taken somehow and I'm looking to figure out why that is. I see it show up in my JpaProperties bean. If I change other properties, like my dialect, I can see that they are taking effect.
Could anyone point me to the code that actually reads that property and makes a decision on what generator to use or point out some obvious error I'm making here?
As it's stated in the documentation:
You need to ensure that names defined under spring.jpa.properties.* exactly match those expected by your JPA provider. Spring Boot will not attempt any kind of relaxed binding for these entries.
For example, if you want to configure Hibernate’s batch size you must use spring.jpa.properties.hibernate.jdbc.batch_size. If you use other forms, such as batchSize or batch-size, Hibernate will not apply the setting.
So, for your case you should use:
spring.jpa.properties.hibernate.id.new_generator_mappings: false
See also this part of hibernate documentation.

Hibernate generated id cause error message : "key already exists"

I'm using spring app with hibernate and postgres to store data. The configuration for the product entity is as follow :
/**
* A Product.
*/
#Entity
#Table(name = "product")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "product")
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
...
}
When I want to create a product using the web app I get the following error duplicate key value violates unique constraint. Detail : the key (id)=(35018) already exists.
From my understanding hibernate use a sequence in db to generate the next id value. So I did SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'; in the psql shell to get all sequence in my db. The output is :
hibernate_sequence
jhi_user_id_seq
key_value_id_seq
jhi_persistent_audit_event_event_id_seq
unit_id_seq
generic_user_id_seq
currency_id_seq
customer_type_id_seq
customer_exploitation_type_id_seq
legal_entity_id_seq
deposit_id_seq
machine_id_seq
tank_id_seq
address_id_seq
product_id_seq
rewarded_file_id_seq
bar_code_type_id_seq
quality_label_id_seq
shop_pdv_id_seq
brand_id_seq
category_id_seq
material_id_seq
ws_call_id_seq
postal_code_id_seq
commune_id_seq
country_id_seq
event_id_seq
event_type_id_seq
key_blob_id_seq
card_id_seq
So I thought nice I have a product_id_seq and I only have to update the value in it for things to work.
But when I request the value with SELECT * FROM product_id_seq; I get :
last_value | log_cnt | is_called
------------+---------+-----------
100616 | 0 | t
So here I think that the id generated for the product id is not coming from this product_id_sequence since it tries to insert a product with id = 35018 and the product_id_seq last value is 100616.
So I wonder where does this id 35018 comes from? Which sequence is used to generate it? My guess is I have to update this mysterious sequence to get things to work. For info the hibernate sequence has a value of 36400.
Any idea that could get me going? Thanks in advance.
You do not map your sequence with postgre sequence so Hibernate creates the sequence hibernate_sequence (the one you got 35018 from) for itself.
To use your existing sequence:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator", sequenceName = "product_id_seq")
private Long id;

Has Spring-boot changed the way auto-increment of ids works through #GeneratedValue?

Spring-Boot 2.0.0 seems to have modified the way Hibernate is auto configured.
Let's suppose two simple and independent JPA entities:
#Entity
class Car {
#Id
#GeneratedValue
private long id;
//....
}
#Entity
class Airplane {
#Id
#GeneratedValue
private long id;
//....
}
Prior, using Spring-Boot 1.5.10, I was able to generate separate sequences of auto-increments, meaning that I can get a Car with 1 as primary key and an Airplane with 1 as primary key too.
No correlation between them, e.g no shared sequence.
Now, with 2.0.0, when I sequentially create a very first Car then a very first Airplane, the car gets 1 as id and airplane gets 2.
It seems that he has to deal with the GeneratedType.AUTO, that is the "used by default" specified within the #GeneratedValue annotation source.
However, my reasoning seems to stop here since GeneratedType.AUTO was also set as default with the 1.5.10.
A simple workaround to fulfil my expectation is to specify the IDENTITY strategy type of generation like so:
#Entity
class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
//....
}
#Entity
class Airplane {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
//....
}
I can't figure out an explanation of this behavior.
What has Spring-boot 2.0.0 changed, explaining this scenario?
Spring Boot 2.0 uses Hibernate 5.2 (https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release-Notes).
Hibernate changes its GeneratedType.AUTO strategy since 5.2. Any database that does not support sequences natively (e.g. MySQL), they use the TABLE generator instead of IDENTITY. (https://hibernate.atlassian.net/browse/HHH-11014)
That's why GeneratedType.AUTO does not work as you expected.
You can use
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
to use MySQL autoincrement.
If you are in need for a quick, not future-proof solution to prevent this issue from happening:
spring.jpa.hibernate.use-new-id-generator-mappings=false, as from the Spring Boot 2 docs:
spring.jpa.hibernate.use-new-id-generator-mappings= # Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE.
This will prevent from using the new generators and keep the old functionality included in Spring boot 1.x.x.
Please note that this is probably not the best solution, but it is very helpful on short term
As Andrew has pointed out in the comment, if you don't want the id to be incremented while values are created in other tables, you can specify your ID like this:
#Id
#GeneratedValue(
strategy= GenerationType.AUTO,
generator="native"
)
#GenericGenerator(
name = "native",
strategy = "native"
)
private Long id;
Doing this will make each table has its unique id beginning with 1,2,3 ... and so on.
By default spring-boot uses the auto and increment the value based on the order the objects are saved.
To provide unique id based on each object, use the following
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

EclipseLink can not insert an entity into oracle

I built an entity with id using oracle sequence like that.
#Entity
#Table(name="C_ESTIMATE")
public class Estimate implements Serializable{
private static final long serialVersionUID = 1L;
public Estimate(){}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "estimatenoGen")
#SequenceGenerator(name="estimatenoGen",sequenceName="AUTOSERIALNO",allocationSize=1)
#Column(name="ESTIMATENO")
private long id;
}
When I call em.persist(new Estimate()),
EclipseLink prompts Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraints . Sometimes it works correctly, sometimes failure, it is so strange.
This entity was deployed several weblogic servers.
Has EclipseLink bug on generating id using oracle sequence?
There should not be any issue on Oracle.
Can recreate the issue? Enable logging, is a duplicate id being used?
How did you create your SEQUENCE object on the database?

sequence does not exist exception using eclipseLink with oracle db

I've got the following JPA entity:
#Entity
#Table(schema = "myschema")
#SequenceGenerator(schema = "myschema", name = "seqGenerator",
sequenceName = "person_s1", allocationSize = 1)
public class Person {
#Id
#GeneratedValue(generator = "seqGenerator", strategy = GenerationType.AUTO)
private long id;
the following exceptions are thrown:
Call: DROP SEQUENCE myschema.person_s1
Query: DataModifyQuery(sql="DROP SEQUENCE myschema.person_s1")
[EL Warning]: 2010-11-01 17:21:51.051--ServerSession(10605044)--Exception [EclipseLink- 4002] (Eclipse Persistence Services - 2.1.1.v20100817-r8050):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-02289: sequence does not exist
Error Code: 2289
Call: SELECT myschema.person_s1.NEXTVAL FROM DUAL
Query: ValueReadQuery(sql="SELECT myschema.person_s1.NEXTVAL FROM DUAL")
The sequence is genrated by EclipseLink and the query:
SELECT myschema.person_s1.NEXTVAL FROM DUAL
works fine when used directly...
Any help appreciated
Regards Marcel
the following exceptions are thrown (...)
These traces are generated during schema creation when a particular database object doesn't exist and thus can't be dropped. EclipseLink report such cases as Warning (which are not Error), they can be ignored (you get your sequence, right?).
PS: Why do you use an allocation size of 1, don't you want to benefit from the high/low optimization?
I know this is going to sound really silly, but here it is anyway.
#Entity
#Table(schema = "myschema")
public class Person {
#Id
#SequenceGenerator(schema = "myschema", name = "seqGenerator", sequenceName = "person_s1", allocationSize = 1)
#GeneratedValue(generator = "seqGenerator", strategy = GenerationType.AUTO)
private Long id;
}

Resources