What side effects occur when reusing generator names? - java

I'm working in a code base of a couple dozen tables. I went to add a new class and, naturally, I'm going to look at what has been written before I got on the project to see how it's done over there. Something about wheel engineering?
Anyway, here's what I find
#Id
#SequenceGenerator(name = "identifier", sequenceName = "LIMIT_REASON_COLL_ID_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "identifier")
#Column(name = "ID")
Of note is the name = "identifier" and generator = "identifier. I didn't replace anything, that's actually what it says. And it's called "identifier" in every class managed by Hibernate.
Now, the system has been stable for years, so clearly it doesn't appear to impact whatever we're doing (that we can observe). But are there any side effects to reusing the generator name in this way? Is it advised, and if it isn't why not?

The SequenceGenerator's name and the GeneratedValue's generator can be whatever you choose to name them.
It's the GeneratedValue's strategy that references one of the Hibernate identifier generators:
increment
identity
sequence
hilo
seqhilo
uuid
uuid2
guid
assigned
select
foreign
There is no association between the generator's name and the strategy. So you can call your sequence generator by the "identity" name.

I think you will face problem related to duplicate key violation.. or somthing like this. Someday before i searched for the same and I got this post : JPA 2 #SequenceGenerator #GeneratedValue producing unique constraint violation . Please go though Question and answer.

Related

UUID primary key for JPA Entity: safe approach to use unique values on multiple instances

I'm using SpringBoot, JPA and Hibernate.
I have a doubt.
For my entities I need to have an UUID as primary key (and I would like to save this id in "clear mode" (string) and not binary)
I'm using this code:
#Id
#Column(name = "id")
#Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();
My doubt is this: Is this approach safe? Can I be sure ids will always be unique?
I understand that, using this code, the UUID will be generated code side so, what's happen if I will have multiple instances for my service using the same DB service for all instances?
Is it possible that more instances will generate the same UUID?
UUID uuid = UUID.randomUUID()
My doubt is this: Is this approach safe? Can I be sure ids will always be unique?
Yes, extremely safe.
A UUID Version 4 has 122 bits of randomly generated data. That is a vast range of numbers. Assuming your UUID is being generated with a cryptographically-strong random number generator, you have no practical concerns with using a randomly-generated UUID.
For details, see the Collisions section on Wikipedia.
If you want to worry, apply your worry to things that are much more likely to happen. Top in my mind: Cosmic rays flipping bits in non-EEC memory. (See valid rant by Linus Torvalds on the issue.)
Personally, I consider the point-in-space-and-time versions such as Version 1 to be even less of a concern for collisions. But others debate this. Either way, Version 1 or Version 4, I would sleep well.
Despite saying the above, you should still ensure that your code is written to be robust in the face of collisions. Not because of collisions from randomly-generated duplicates, but because of collision from the all-too-human possibilities such as a bug in your code that double-posts the record to database, or a DBA who mistakenly loads back-up data twice, and so on.
I'm not a hibernate specialist, however, if you do it like this, in general, it should be kind of ok, which means that the probability of collision is low, however "what if" there is a collision? In other words, you can't be 100% sure that you're "guaranteed to avoid collision". If your system can deal with collision (re-create a UUID for example, assuming that performance penalty is negligible because this will happen in extremely rare cases) then no problem of course.
Now the real question is whether there is something else that can be done here?
Well, Hibernate is able to generate the UUID in a way that also uses an IP of the machine as a parameter of generation:
#Entity
public class SampleEntity {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator",
parameters = {
#Parameter(
name = "uuid_gen_strategy_class",
value = "org.hibernate.id.uuid.CustomVersionOneStrategy"
)
}
)
#Column(name = "id", updatable = false, nullable = false)
private UUID id;
…
}
For more information read here for example
Of course, the best approach would be to let the DB deal with the ID generation. You haven't specified which database do you use. For example, Postgresql allows generating UUID keys with the help of extension:
Read here for example.
In general, using the UUID is not always a good idea - it's hard to deal with them in day-to-day life, and in general they introduce an overhead that might be significant if there are many rows in the table. So you might consider using an auto-increment sequence or something for the primary key - DB will be able to do it and you won't need to bother.

Hibernate GenerationType.IDENTITY vs GenerationType.SEQUENCE

I'm looking for clarification on this question: #GeneratedValue(strategy="IDENTITY") vs. #GeneratedValue(strategy="SEQUENCE") (nearly a decade old has anything changed?)
Getting started with learning jpa, the following generation types both seem to auto-increment the primary keys that get generated by 1.
Identity:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Sequence:
#Id
#SequenceGenerator(
name = "my_sequence",
sequenceName = "my_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "my_sequence"
)
private Long id;
I understand that the sequence object created by GenerationType.SEQUENCE is not tied directly to a table in the way GenerationType.IDENTITY is. The old question mentions that sequence can be more flexible. Are there any objective pros or cons to choosing one of these strategies over the other? Also anything new considering the age of the question being referenced?
As it's stated in the hibernate documentation:
It is important to realize that using IDENTITY columns imposes a runtime behavior where the entity row must be physically inserted prior to the identifier value being known.
This can mess up extended persistence contexts (long conversations). Because of the runtime imposition/inconsistency, Hibernate suggests other forms of identifier value generation be used (e.g. SEQUENCE).
There is yet another important runtime impact of choosing IDENTITY generation: Hibernate will not be able to batch INSERT statements for the entities using the IDENTITY generation.
The importance of this depends on the application-specific use cases. If the application is not usually creating many new instances of a given entity type using the IDENTITY generator, then this limitation will be less important since batching would not have been very helpful anyway.

Exception : The field can't be empty (null) [duplicate]

#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Why we are using this annotations?
i need to know if this autoincrement my table id values.
(GenerationType.IDENTITY) is there any other types whats actually happening when we use this annotation
public class Author extends Domain
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#Column(name = "name")
private String name;
#Column(name = "address")
private String address;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "authorId")
private List<Book>
bookList;
public Author()
{
setServiceClassName("wawo.tutorial.service.admin.AuthorService");
}
}
*Is it necessary to extend Domain abstract class?What is the use?
First of all, using annotations as our configure method is just a convenient method instead of coping the endless XML configuration file.
The #Idannotation is inherited from javax.persistence.Id, indicating the member field below is the primary key of current entity. Hence your Hibernate and spring framework as well as you can do some reflect works based on this annotation. for details please check javadoc for Id
The #GeneratedValue annotation is to configure the way of increment of the specified column(field). For example when using Mysql, you may specify auto_increment in the definition of table to make it self-incremental, and then use
#GeneratedValue(strategy = GenerationType.IDENTITY)
in the Java code to denote that you also acknowledged to use this database server side strategy. Also, you may change the value in this annotation to fit different requirements.
1. Define Sequence in database
For instance, Oracle has to use sequence as increment method, say we create a sequence in Oracle:
create sequence oracle_seq;
2. Refer the database sequence
Now that we have the sequence in database, but we need to establish the relation between Java and DB, by using #SequenceGenerator:
#SequenceGenerator(name="seq",sequenceName="oracle_seq")
sequenceName is the real name of a sequence in Oracle, name is what you want to call it in Java. You need to specify sequenceName if it is different from name, otherwise just use name. I usually ignore sequenceName to save my time.
3. Use sequence in Java
Finally, it is time to make use this sequence in Java. Just add #GeneratedValue:
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
The generator field refers to which sequence generator you want to use. Notice it is not the real sequence name in DB, but the name you specified in name field of SequenceGenerator.
4. Complete
So the complete version should be like this:
public class MyTable
{
#Id
#SequenceGenerator(name="seq",sequenceName="oracle_seq")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
private Integer pid;
}
Now start using these annotations to make your JavaWeb development easier.
In a Object Relational Mapping context, every object needs to have a unique identifier. You use the #Id annotation to specify the primary key of an entity.
The #GeneratedValue annotation is used to specify how the primary key should be generated. In your example you are using an Identity strategy which
Indicates that the persistence provider must assign primary keys for
the entity using a database identity column.
There are other strategies, you can see more here.
Simply, #Id: This annotation specifies the primary key of the entity.
#GeneratedValue: This annotation is used to specify the primary key generation strategy to use. i.e Instructs database to generate a value for this field automatically. If the strategy is not specified by default AUTO will be used.
GenerationType enum defines four strategies:
Generation Type . TABLE,
Generation Type. SEQUENCE,
Generation Type. IDENTITY
Generation Type. AUTO
GenerationType.SEQUENCE
With this strategy, underlying persistence provider must use a database sequence to get the next unique primary key for the entities.
GenerationType.TABLE
With this strategy, underlying persistence provider must use a database table to generate/keep the next unique primary key for the entities.
GenerationType.IDENTITY This GenerationType indicates that the persistence provider must assign primary keys for the entity using a database identity column. IDENTITY column is typically used in SQL Server. This special type column is populated internally by the table itself without using a separate sequence. If underlying database doesn't support IDENTITY column or some similar variant then the persistence provider can choose an alternative appropriate strategy. In this examples we are using H2 database which doesn't support IDENTITY column.
GenerationType.AUTO This GenerationType indicates that the persistence provider should automatically pick an appropriate strategy for the particular database. This is the default GenerationType, i.e. if we just use #GeneratedValue annotation then this value of GenerationType will be used.
Reference:- https://www.logicbig.com/tutorials/java-ee-tutorial/jpa/jpa-primary-key.html
Why are we using this annotation?
First I would like to remind everyone that the annotations, such as #Id, are providing metadata to the persistence layer(I will assume hibernate).This metadata will most likely be stored in the .class file(but not stored in the database) and is used to tell hibernate how to recognize, interpret and manage the entity. So, Why are you using the annotation? To provide your persistence layer with the proper information about how to manage the entity.
Why use the #Id annotation?
The #Id annotation is one of the two mandatory annotations needed when creating an entity with JPA. The other one being #Entity. #Id does two things for us:
1) signifies that this field will be the unique identifier for this class when mapped to a database table
2) the presence of #Id lets the persistence layer know that all other fields within this class are to be mapped to database rows
Why use #GeneratedValue?
By marking the #Id field with #GeneratedValue we are now enabling id generation. Which means that the persistence layer will generate an Id value for us and handle the auto incrementing. Our application can choose 1 of 4 generations strategies:
1) AUTO
2) TABLE
3) SEQUENCE
4) IDENTITY
If not strategy is specified then AUTO is assumed
What is strategy = GenerationType.IDENTITY actually doing?
When we specify the generation strategy as GenerationType.IDENTITY we are telling the persistence provider(hibernate) to let the database handle the auto incrementing of the id. If you were to use postgres as an underling database and specified the strategy as IDENTITY, hibernate would execute this:
create table users (
id bigserial not null,
primary key (id)
)
Notice that they type of the id is bigserial, what is bigserial? As per the postgres documentation, bigserial is a large autoincrementing integer.
Conclusion
By specifying:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
you have told the underlying persistence layer to use the id field as a unique identifier within the database. Also told the persistence layer to let the database handle the auto incrementing of the id with GenerationType.IDENTITY.
In very simple words, we want to tell our Database (DB) what strategy to use to generate primary keys.
Now, primary keys must be different for every different row so there must be some strategy that will tell the DB on how to differentiate one row from another.
GenerationType lets us define that strategy.
Here #GeneratedValue(stratergy=GenerationType.IDENTITY) is telling our DB to store primary key in the identity column which is a default column in SQL for default auto incremented primary key generation.

Java JPA (EclipseLink) How to receive the next GeneratedValue before persisting actual entity?

I'm using the EclipseLink implementation of JPA and I've got a problem.
Here is my entity class:
#Entity
#Table(name = "attendances")
public class Attendance implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Short id;
....
In my MySQL table (that is the underlying data store) I have auto_increment flag also set.
How can I get the auto-generated value (id field) before persisting the entity? So if there are 3 entities in the table (id IN (1, 2, 3)), I want to get 4 as the next auto-generated value.
The only workaround I have is:
Get the id of the entity with the largest id field.
Is that all I can do?
You can try this, if using JPA 2.0,
entityManagerFactory.getPersistenceUnitUtil().getIdentifier(attendance);
DISCLAIMER: Never tried it myself.
Otherwise, you can change your id generation strategy to something, that can get you the id before persisting the entity. For example, try to use table generator to generate your ids. Here, I found an example, Use Table Generator To Generate ID. Then you would be able to read the value from that table, directly. You may not be able to handle this automatically using #Id, precisely you will end up calculating the next id yourself. Hence, you can employ the same idea but do all the work yourself and set the id while creating the operation, and don't let JPA to generate one.
Or you might like to use the sequence, if supported. In case of sequence also you need to get the next value yourself and set it manually. Be prepared to loose skipped ids in case of no insert, or handle that somehow.
Or you are fine with what you are doing. Just take care of atomicity. Or you may not have the case of multiple transactions running simultaneously.

What's the reason behind the jumping GeneratedValue(strategy=GenerationType.TABLE) when not specifying a #TableGenerator?

Why do I need to add allocationSize=1 when using the #TableGenerator to ensure that the id wouldn't jump from 1, 2,... to 32,xxx, 65,xxx,... after a jvm restart?
Is there a design reason for the need to specify the allocationSize?
This snippet would produce the jumping ids
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
Here's the modified snippet that produces the properly sequenced ids
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "account_generator")
#TableGenerator(name = "account_generator", initialValue = 1, allocationSize = 1)
private Long id;
Hibernate caches a block of ids for performance reasons. It allocates several ids from database, keeps and if these run out it allocates another block from sequence (thus increasing the sequence value)
I'm not claiming it is the case but this might be a bug in the underlying generator used by Hibernate. See for example this post on Hibernate's forums that describes a weird behavior, the issues mentioned in the comments of the New (3.2.3) Hibernate identifier generators or existing issues in Jira.
My suggestion would be to identify the generator used in your case and to search for an existing issues or to open a new one.

Categories