Why and how hibernate_sequence is using for id generatior - postgresql

I'm faced out an issue with ID generation for my entities generated by JHipster:
Dev environment on H2 database
Prod environment on Postgres
I have one entity "station" with two fields "id" and "name"
Creating a liquibase script which imports dictionary in "station" table like
INSERT INTO station (name) VALUES ('Adygeya') without ID definition
Trying to add station on dev environment - OK
Trying to add station on prod - Hibernate tries to add new station with duplicated ID
WHY?
My research was shown that only for postgres and oracle in initial scheme jhipster created a new sequince "hibernate_sequence" which is used for new entities creation.
So I'm fixed out this wrong behaivour by adding specific sequence name for my entity ID generation rule
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "station_gen")
#SequenceGenerator(name = "station_gen", sequenceName = "station_id_seq")
private Long id;
Now I have just 3 questions:
Why JHipster using one sequince for all tables for postgres and oracle?
Where is it configured?
What am I doing wrong?

Will post here my answer wich was found with help of #GaƫlMarziou and #Julien Dubois.
Thats because of history and default behaivour of Hibernate hilo algorithm with GenerationType.AUTO. MySQL doesn't support sequencies so JHipster needs to use this stupid algorithm
JHipster team has found right solution wich will fix my problem. The solution is to use GenerationType.SEQUENCE for all DB but use GenerationType.IDENTITY for MySql. All the details in this commit https://github.com/jhipster/generator-jhipster/commit/4516b4ff4d49a96a75fd963b0c7667f198bd9b79
This way I will configure my entities now too.

Related

Spring Boot Hibernate Problem with generating entity ID using sequence or identity

I am developed Rest API with sprint boot, jpa, hibernate and PostgreSQL. My goal is to be able to generate auto-incremented id for using with code and using database tool such as D Beaver without writing any extra queries for getting next ID value and etc.
I have created entity User. I tried generating id in two ways:
GenerationType.IDENTITY
When using GenerationType.IDENTITY it successfully creates table with name user, sequence with name user_id_seq and adds a default value for user.id column nextval('user_id_seq'::regclass). Everything in database is as expected and it works great with database tool, but problem occurs when I am trying to insert new row from my API. When trying to insert new row hibernate executes query
select currval('user_id_seq')
to get id value and I am getting error
org.postgresql.util.PSQLException: ERROR: invalid name syntax
because of those quotes around user. It should execute
select currval('user_id_seq')
I believe that the problem here is because I use table name user which is a reserved keyword, but I want to keep it this way because this naming matches other tables pattern.
GenerationType.SEQUENCE
If I use annotations:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_generator")
#SequenceGenerator(name="user_generator", sequenceName = "user_id_seq", allocationSize=1)
it creates table 'user', sequence 'user_id_seq' but doesn't add user.id column default value, so I can't insert new rows using database tool without specifying id value. But using this generation type my API works fine.
It is also worth mentioning that I am using spring.jpa.hibernate.ddl-auto=create-drop and manually dropping and recreating schema each time so there wouldn't be any unnecessary sequences/tables left.
#Entity
#Table(name = "`user`")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// other properties...
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
// other getters and setters...
}
So... It is possible to somehow connect those two ways and create one working solution? I need to have default value for column and that hibernate would also know how to generate that id.
P.S. I don't want to change table/entity naming or execute SQL to correct tables when running application. I believe that there should be a better approach.
After a lot of hours of debugging I ended up extending PostgreSQL82Dialect and overriding getIdentitySelectString function to remove quotes from table name.

Generate Hibernate Envers primary key manually and jpa as well

My project is migrating from Grails to Java so I have exisiting Audit data in a single table pushed by Grails Audit plugin, now I am using Java envers for Auditing in java. I have below doubts:
-> If i want to push data from single table to different Audit tables(in Java) manually, how can i generate Primary key of revision table for history data manually which will not collide with primary key generated from Java annotation?
As for new entries I am generating primary key like below:
#Id
#GeneratedValue
#RevisionNumber
#Column(name = "ID") #NotNull
private Long revisionId;
-> Any other way to push data from single audit table to segregated Audit tables(In java) instead of doing it manually?
Please let me know about this.
Thanks.
Envers should be creating sequence named REVISION_LISTENER on Oracle.
Therefore you should be able to use Oracle's syntax SELECT REVISION_LISTENER.NEXTVAL in order to get the next sequence value and use that in the REV field both in your audit table and the revision entity info table too.
This only applies to DefaultAuditStrategy.
If you intend to use the ValidityAuditStrategy, there are other fields which you'll have to understand the internals of Envers in order to be able to populate the relevant fields. If you are using this strategy, let me know and I'll add more details that are specific to it, but its very complex and quite tedious.

JPA and PostgreSQL with GenerationType.IDENTITY

I have a question about Postgres and GenerationType.Identity vs Sequence
In this example...
#Id
#SequenceGenerator(name="mytable_id_seq",
sequenceName="mytable_id_seq",
allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="mytable_id_seq")
I understand that I am specifying a Postgres sequence to use via annotations.
However, I have an id column defined with the 'serial' type, I have read that I can simply use GenerationType.IDENTITY and it will automatically generate a db sequence and use it to auto increment.
If that's the case, I don't see an advantage to using the SEQUENCE annotations unless you are using an integer for an id or have some specific reason to use another sequence you have created. IDENTITY is alot less code and potentially makes it portable across databases.
Is there something I'm missing?
Thanks in advance for the feedback.
If you have a column of type SERIAL, it will be sufficient to annotate your id field with:
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
This is telling Hibernate that the database will be looking after the generation of the id column. How the database implements the auto-generation is vendor specific and can be considered "transparent" to Hibernate. Hibernate just needs to know that after the row is inserted, there will be an id value for that row that it can retrieve somehow.
If using GenerationType.SEQUENCE, you are telling Hibernate that the database is not automatically populating the id column. Instead, it is Hibernate's responsibility to get the next sequence value from the specified sequence and use that as the id value when inserting the row. So Hibernate is generating and inserting the id.
In the case of Postgres, it happens that defining a SERIAL column is implemented by creating a sequence and using it as a default column value. But it is the database that is populating the id field so using GenerationType.IDENTITY tells Hibernate that the database is handling id generation.
These references may help:
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators
https://www.postgresql.org/docs/8.1/static/datatype.html#DATATYPE-SERIAL
From "Pro JPA2" book:
"Another difference, hinted at earlier, between using IDENTITY and other id generation strategies is that the identifier will not be accessible until after the insert has occurred. Although no guarantee is made about the accessibility of the identifier before the transaction has completed, it is at least possible for other types of generation to eagerly allocate the identifier. But when using identity, it is the action of inserting that causes the identifier to be generated. It would be impossible for the identifier to be available before the entity is inserted into the database, and because insertion of entities is most often deferred until commit time, the identifier would not be available until after the transaction has been committed."
I think it can be helpful if you are using the same sequence for more than one table (for example you want a unique identifier for many types of bills) ... also If you want to keep track of the sequence away from the auto generated key
You can find here the solution of updating the PostgreSQL table creation accordingly, in order to work with the GenerationType.IDENTITY option.

JPA EclipseLink table creation order

I have a working project that uses JPA to persist data on MySQL (EclipseLink as provider). Recently I wanted to drop the database and create it again with the tables via Eclipse => EclipseLink 'Generate tables from entities'. I also have the persistence.xml updated (first generated automatically, then modified manually to narrow down on this problem).
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>xxx.entity.options.Difficulty</class>
<class>xxx.entity.options.Options</class>
(Omitted the rest since it is ok otherwise => it is working in general)
The problem is that when I generate the tables I get the error:
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'xxx.DIFFICULTY' doesn't exist
Error Code: 1146
(The entity classes have table names defined:
#Entity
#Table(name = "DIFFICULTY"))
If I comment out the 'Options' from persistence.xml, the 'DIFFICULTY' table gets created ok. Then uncommenting 'Options' again and re-generating the tables => the 'OPTIONS' table will be created also (Options has #ManyToOne association with the Difficulty).
In the persistence.xml I have
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
as I am still developing.
In the Options class I have
#ManyToOne(optional = false, cascade = CascadeType.REFRESH, fetch = FetchType.LAZY)
private Difficulty difficulty = null;
(Many Options are suppose to have the same Difficulty selected, so none really owns one. I hope this is correct?)
After The Difficulty and Options tables were created successfully, I was able to re-create the rest of the database tables.
The question is that should I (be able to) specify the order in which the tables are created?
Have I something wrong with the #ManyToOne association?
Already spent couple of hours on this issue, but couldn't figure it out what is the problem.
Sorry for the long text, I just try to explain the whole situation.
Last time I received 'tl; dr;' answer (didn't know by that time what it meant), I spent 6 hours looking the wrong thing, so please do not bother to answer in such case.
If you look at the exceptions stack, you'll see it is coming from your entity's default constructor. This constructor is trying to issue a query by obtaining an entitymanager, and is failing because the table it needs doesn't exist yet. When you create that one table, the constructor can query it, which allows everything to proceed.
You should not have business logic in your default constructor. This is used by the provider, and is getting called during deployment before DDL. Removing that will resolve the issue.
Are you changing the class/schema in between your last create? It could be that you have added or removed new relationships, so EclipseLink is not able to drop the old constraints.
For drop-and-create-tables EclipseLink will basically do the following,
drop known constraints
drop known tables
create known tables
create known constraints
In the latest release EclipseLink will try a couple drop passes to try and handle unknown constraints, but the best method for a rapidly changing development schema would be to drop the entire schema in between deployments.

Postgresql/openJPA (geronimo) Sequence Issue

I am having a weird problem with a sequence. Im using postgresql 9 with geronimo 2.2. I have created the sequence PLANTS_ID_SEQ inside the db environment and when I try to create a new entity I get an error in my logs (which comes from postegresql) that the relation PLANTS_ID_SEQ exists. It seems that it tries to create the sequence that is already created. This is the code from the entity bean:
#Id
#GeneratedValue(generator="PLANTS_SEQ",strategy=GenerationType.SEQUENCE) #SequenceGenerator(name="PLANTS_SEQ", sequenceName="PLANTS_ID_SEQ",allocationSize=1) #Column(name = "ID")
private Integer id;
Please notice that if I change the sequence name (eg sequenceName="MY_SEQ")then the code runs correctly but it creates in postgresql (and obviously uses) the MY_SEQ sequence. If anyone has a clue about this case please share.
Thanks George
If your table has a column of type SERIAL, then postgres will create the sequence for you and use it automatically on inserts.
The sequence it creates is named "tablename_id_seq"...
Probably you're trying to duplicate what postgres has already done, and create a duplicate sequence.
Solved:
Should add in persistence.xml the following property:
property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(Sequences=false)"
this way, the MappingTool of openjpa will not try to create the sequence again.