"hibernate_sequence" does not exist" - postgresql

I am getting "ERROR: relation "hibernate_sequence" does not exist" exception while doing insert operation.
Technical Stack
-> Springboot
-> Hibernate
-> PostgreSQL
Approaches tried so far.
-> Verified all entity classes in project, generation strategy is used as "#GeneratedValue(strategy = GenerationType.IDENTITY)".
-> Verified database tables, pk is either Serial or Int with proper sequence generated value.
-> Tried with use-new-id-generator-mappings property as false, didn't worked.
-> Verified sequence with name "hibernate_sequence" is available in Database.
Analysis so far
-> Entities those are annotated with #Audited having this issue as hibernate envers expect global "hibernate_sequence". But not able to find the exact solution.
Note : This was working few days back without any issue, Since last week started getting this issue.

As you said, hibernate-envers is looking for the hibernate_sequence.
Its used to insert records into the REVINFO table
Assuming spring.jpa.hibernate.ddl-auto is not set to create
either
create a hibernate_sequence manually
create a sequence with the name you want. e.g rev_id_seq. Then override the REVINFO definition to change the sequence name by adding your definition of the RevisionEntity
#Entity
#RevisionEntity
public class MyRevision implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "rev_id_generator")
#SequenceGenerator(name = "rev_id_generator", sequenceName = "rev_id_seq", allocationSize = 1)
#RevisionNumber
private int id;
#RevisionTimestamp
private long timestamp;
// Getters, setters, equals, hashCode ...
}
https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#envers-tracking-modified-entities-revchanges
https://thorben-janssen.com/hibernate-envers-extend-standard-revision/

Initially set the spring.jpa.hibernate.ddl-auto to create for the first time and run the application. It will create the hibernate sequence. after that change spring.jpa.hibernate.ddl-auto to none. It will prevent any further data loss from tables. Or you can set to update if necessary.

Because you are using #GeneratedValue()
It will look for how the database that you are using generates ids. For MySql or HSQSL, there are increment fields that automatically increment. In Postgres or Oracle, they use sequence tables. Since you didn't specify a sequence table name, it will look for a sequence table named hibernate_sequence and use it for default. So you probably don't have such a sequence table in your database and now you get that error.
I Also got this working using;
#GeneratedValue(strategy = GenerationType.IDENTITY)

I faced the exact same issue when I migrated from Maria to Postgres. Either/both problems one may have:
Schema name is not in the connection URL
If the schema name isn't passed flyway_schema_history table and sequences were created under the public schema. And application tables were made under the custom schema.
So make sure you have the required schema configured.
spring:
datasource:
url: jdbc:postgresql://localhost:5432/platform?currentSchema=product1
username: admin
password: admin
driver-class-name: org.postgresql.Driver
flyway:
schemas:
- product1
Sequence got created but with another name
This was the problem for me. Sequence got created with the name revinfo_rev_seq. However, while inserting the records it was looking for hibernate_sequence.
I added another revision under flyway migration to rename the already created sequence.
-- This is not required for MySQL/MariaDB. However, while using PostgresSQL getting the error -> ERROR: relation "hibernate_sequence" does not exist
ALTER SEQUENCE revinfo_rev_seq RENAME TO hibernate_sequence;

Related

Postgres Partitioning not working with hibernate if id is bigserial

I have partitioned my table in Postgres. So there are 2 tables now :
Base table users , with no primary key but using a sequence generator for id column : nextval('users_id_seq'::regclass)
Child table inheriting users
CREATE TABLE users_part_2019_01 (
CHECK (createdon >= '2019-01-01 00:00:00'
AND createdon < '2019-02-01 00:00:00')
) INHERITS (users);
ALTER TABLE users_part_2019_01 ADD CONSTRAINT users1_pkey PRIMARY KEY (id);
I am inserting data into users table using jpa. In the data model I have used :
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Getting the following error :
"org.springframework.orm.jpa.JpaSystemException: The database returned
no natively generated identity value; nested exception is
org.hibernate.HibernateException: The database returned no natively
generated identity value
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)"
It is working as expected independently with postgres.
Got the solution. Instead of GenerationType.IDENTITY, GenerationType.AUTO is working
In case you are coming here from spring boot (2.2.x +) and using postgresql partitioning, the accepted answer alone is not enough to make it work. Hibernate, in this case, will throw the following:
Schema-validation: missing sequence [schema_name.hibernate_sequence]
In this case, the hibernate simply wants you to provide the identity generator for the sequence field by passing it as:
#GeneratedValue(strategy = GenerationType.AUTO, generator = "schema_name.generator_sequence_name_seq")

Use Sequence created by Flyway in JPA

I'm using a Spring Boot 2 / Flyway / Postgres setup.
I want to achieve to let Flyway create a table with a sequence for automatic key iteration. JPA should recognize the sequence and use it.
I let Flyway execute a PostgreSQL script:
CREATE SEQUENCE config_id_seq;
CREATE TABLE config
(
ID BIGINT NOT NULL PRIMARY KEY DEFAULT nextval('config_id_seq'),
DESCRIPTION VARCHAR(500)
);
And this is the Entity definition:
#Entity
#Table(name = "config")
public class Config {
#Id
#SequenceGenerator(name = "config_id_sequence", sequenceName = "config_id_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "config_id_sequence")
#Column(name = "id")
private long id;
#Column(name = "description")
private String description;
On start up the following errors are thrown:
Caused by: org.postgresql.util.PSQLException: ERROR: relation "config_id_seq" already exists
Caused by: org.postgresql.util.PSQLException: ERROR: cannot change sequence "config_id_seq"
My interpretation is that Flyway successfully executed the script and created a sequence. But JPA wants to create the sequence afterwards and fails because it already exists. Please, correct me if I'm wrong here.
Now how can I configure JPA to reuse the existing sequence, if this is possible?
We need to set spring.jpa.hibernate.ddl-auto property to none or you can skip this property so that spring does not create database objects on its own.
If we are using a flyway then we should give the responsibility of database objects creation to flyway only i.e create all database objects with flyway scripts only like tables and sequence.
Specifying GeneratedValue says for JPA to use a sequence, retrieve the next value itself, and then use that in the INSERT.
But make sure you have the same configuration that you mentioned on entity class and flyway script.

JPA #Id #GeneratedValue annotations vs DB primary key?

I have an app accessing an existing MySQL DB utilizing JDBC and am converting to JPA. My DB is already setup with primary keys which are auto generated. Do I need to annotate my entity classes w/ #Id, #GeneratedValue... when this is already defined in the DB? Will the annotations override / conflict with the DB primary key / indexes already defined?
It not going to conflict with the DB primary key and the JPA annotations.Since primary key is already indexed, it's not a problem at all.
You should add annotations in entity classes.It is not going to conflict with already defined DB.If you deploy the system in new DB environment then annotations must be needed.
I assume you are using autonumbers in MySQL and these are autogenerated.
The following code will do what you require:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "table_id")
Notice the GenerationType.IDENTITY strategy? This tells JPA to use the autogenerated database values.

Why does EclipseLink support the #CascadeOnDelete with #ElementCollection?

I have the following embeddable class that contains an #Lob:
#Embeddable
public class EntityState {
private Integer version;
#Lob
#XmlJavaTypeAdapter(CharArrayAdapter.class)
private char[] xmlState;
...
}
I also have the following embeddable class that contains the above embeddable:
#Embeddable
public class EntityEvent {
#NotNull
private String note;
private EntityState entityState;
...
}
Finally, I have many entity classes that contain a property called history that is a list of EntityEvents. The following is an example:
#Entity
public class Company {
#NotNull
#ElementCollection
private List<EntityEvent> history;
...
}
When I deploy my application in GlassFish 4.1, EclipseLink creates the following tables in my Derby 10.11.1.1 database:
COMPANY
COMPANY_HISTORY
When I create a new Company, my application creates an EntityEvent and adds the EntityEvent to the Company history.
When I modify a Company, my application does the following:
Creates an EntityState object and sets the xmlState property to an XML representation of the unmodified entity.
Creates an EntityEvent object containing the above EntityState.
Adds the EntityEvent to the Company history.
The problem is that when I try to delete an entity that has a history with multiple EntityEvents I receive the following error:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLSyntaxErrorException: Comparisons between 'CLOB (UCS_BASIC)' and 'CLOB (UCS_BASIC)' are not supported. Types must be comparable. String types must also have matching collation. If collation does not match, a possible solution is to cast operands to force them to the default collation (e.g. SELECT tablename FROM sys.systables WHERE CAST(tablename AS VARCHAR(128)) = 'T1')
Error Code: 20000 Call: DELETE FROM Company_HISTORY WHERE ((((((((((CHANGES = ?) AND (CLIENTTYPE = ?)) AND (CREATED = ?)) AND (IPADDRESS = ?)) AND (NOTE = ?)) AND (TYPE = ?)) AND (VERSION = ?)) AND (XMLSTATE = ?)) AND (CREATER_ID = ?)) AND (Company_ID = ?)) bind => [10 parameters bound]
I found a few references to the issue in the following links:
Hibernate - #ElementCollection - Strange delete/insert behavior
http://eclipse.1072660.n5.nabble.com/Customizing-delete-calls-before-updating-a-ElementCollection-td7312.html
I tried the #OrderColumn technique described in the above referenced stackoverflow article but this did not work in EclipseLink.
The solution that work for me was to add the EclipseLink nonstandard #CascadeOnDelete annotation to my entity as shown below:
#Entity
public class Company {
#NotNull
#ElementCollection
#CascadeOnDelete
private List<EntityEvent> history;
...
}
After performing this change and rebuilding my database, my COMPANY_HISTORY table has a new definition:
Without #CascadeOnDelete
ALTER TABLE COMPANY_HISTORY ADD CONSTRAINT CMPNYHISTORYCMPNYD FOREIGN KEY (COMPANY_ID) REFERENCES COMPANY (ID);
With #CascadeOnDelete
ALTER TABLE COMPANY_HISTORY ADD CONSTRAINT CMPNYHISTORYCMPNYD FOREIGN KEY (COMPANY_ID) REFERENCES COMPANY (ID) ON DELETE CASCADE;
The solution to my problem surprised me because it seems repetitive. My understanding is that JPA should delete all embeddables associated with an entity when the entity is deleted. The fact that EclipseLink has this nonstandard annotation as documented in the following link makes me think that EclipseLink has a bug and instead of fixing the bug created a new #CascadeOnDelete annotation so that the bug would be covered up by the databases cascading delete functionality.
http://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/a_cascadeondelete.htm
So my question is why. Why does EclipseLink support the #CascadeOnDelete with #ElementCollection?
CascadeOnDelete is simply a feature that specifies that you have specified the "On Delete Cascade" option in your tables, so that JPA does not need to issue SQL to delete the corresponding references. This SQL can apply to any reference, which is why CascadeOnDelete works on an element collection mapping and any other referene mapping.
Your issue has to do with lob comparison limitation in your database, and since there isn't an ID field to uniquely identify element collection rows, this limitation interferes with the way EclipseLink tries to ensure it is only removing the required rows. If you were willing to add an order column to your table, why not just make the EntityEvent an Entity? Or you can customize EclipseLink as described here so that it uses the foreign key and an orderBy field or any combination of fields as a primary key to uniquely identify rows instead of including the lob field.

Meaning of #GeneratedValue with strategy of TABLE

The JPA specification gives the following explanation of the annotation #GeneratedValue(strategy=TABLE):
The TABLE generator type value indicates that the persistence provider must assign primary keys for the entity using an underlying database table to ensure uniqueness.
But what does "using an underlying database table" mean in practice? Does it mean using an auxiliary table? Or by scanning the entity-table to find an ID not in use? Or something else?
Check out JavaDoc for TableGenerator, it has a nice example of how it works:
Example 1:
#Entity public class Employee {
...
#TableGenerator(
name="empGen",
table="ID_GEN",
pkColumnName="GEN_KEY",
valueColumnName="GEN_VALUE",
pkColumnValue="EMP_ID",
allocationSize=1)
#Id
#GeneratedValue(strategy=TABLE, generator="empGen")
int id;
...
}
Example 2:
#Entity public class Address {
...
#TableGenerator(
name="addressGen",
table="ID_GEN",
pkColumnName="GEN_KEY",
valueColumnName="GEN_VALUE",
pkColumnValue="ADDR_ID")
#Id
#GeneratedValue(strategy=TABLE, generator="addressGen")
int id;
...
}
Basically ID_GEN is an internal (non-business) table of key-value pairs. Every time JPA wants to generate ID it queries that database:
SELECT GEN_VALUE
FROM ID_GEN
WHERE GEN_KEY = ...
and incremenets the GEN_VALUE column. This mechanism can be used to emulate sequences or to take even further control of generated ids.
In the case of EclipseLink, it uses an auxiliary table. The documentation says
By default, EclipseLink chooses the TABLE strategy using a table named SEQUENCE, with SEQ_NAME and SEQ_COUNT columns