Hibernate having issues with sequence object - unable to call next val - java

I am using hibernate entity - and sequence generator with it.
My database is Oracle 12c.
In my sequence generator - it fetches value which is already present in table.
I tried looking out for issue - found one simmilar thread
Hibernate sequence nextVal resolved but not used (Oracle)
But still it did not help . The issue am facing is - it works some times and it does not work some times
Below is my code snippet -
#Entity
#Table(name="TABLE_NAME", schema = "SCHEMA")
#SequenceGenerator(name="TABLE_ID_SEQ_GEN", sequenceName="SCHEMA.TABLE_ID_SEQ",allocationSize=1)
public class ImportTransactionDataEntity {
#Id
#Column(name="TABLE_ID",unique=true,nullable=false)
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="TABLE_ID_SEQ_GEN" )
private int IDColumnPk;
ANy help is appreciated , thank you :)

According to Oracle documentation, the #SequenceGenerator should be added to the field, not to the class:
https://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cmp30cfg001.htm#BCGGHADG
so something like:
#Entity
#Table(name="TABLE_NAME", schema = "SCHEMA")
public class ImportTransactionDataEntity {
#Id
#Column(name="TABLE_ID",unique=true,nullable=false)
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="TABLE_ID_SEQ_GEN" )
#SequenceGenerator(name="TABLE_ID_SEQ_GEN", sequenceName="SCHEMA.TABLE_ID_SEQ",allocationSize=1)
private int IDColumnPk;
This works for me.

try this
#Entity
#Table(name="TABLE_NAME")
#SequenceGenerator(name="TABLE_ID_SEQ_GEN",sequenceName="TABLE_ID_SEQ",allocationSize=1)
public class ImportTransactionDataEntity {
#Id
#Column(name="TABLE_ID",unique=true,nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO,generator="TABLE_ID_SEQ_GEN" )
private int IDColumnPk;
it is stored in you database like this the last nummber is the last id used so dont worry about loosing count cause the database does that for you

well finally - i had come to a solution that i was already using oracle 12 C - decide to go with Identity column on the table it self .
NOTE - but the identity column is not available before Oracle 12c .
I ended up getting better performance also with some fraction , so this work around was sigh of relief for me
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TABLE_ID", updatable = false, nullable = false)
private int IDColumnPk;

Related

Creating sequence in Oracle Programmatically using JPA

I am using spring-boot-starter-data-jpa in my Spring boot project to handle DB stuff.
I want to create a sequence in Oracle programmatically.
I have seen many solution which create sequence using raw query but i want to create a sequence from the code. Is there anything i can do using JPA.
I also want to get this sequence number and return it to the caller.
Thanks in advance!!!
First of all, you have to allow Hibernate (one of the JPA implementations available in spring-boot-starter-data-jpa) create DDL statements, so in application.properties:
spring.jpa.hibernate.ddl-auto=create
Note that it is not recommended for production.
Next, annotate your entity in following way:
#Entity
public class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "my_generator")
#SequenceGenerator(name = "my_generator", sequenceName = "MY_SEQUENCE", allocationSize = 1)
private Long id;
//...
}
Once your application will start, hibernate based on your ddl-auto configuration will create the sequence for you:
Hibernate: create sequence MY_SEQUENCE start with 1 increment by 1
You can read more about ddl-autoconfigurations here.

Hibernate sequence not generated

Im working on a Spring (not Boot!) project, with Hibernate and PostgreSQL database. I also use Flyway for migration.
I use Flyway to generate the schema of the database, and insert initial data to it with given SQL scripts in my resources folder. For this reason, I excluded the hibernate.hbm2ddl.auto property from my hibernate.properties file.
On the startup, the schema is created and the data is inserted to the database, but my problem is, that this way Hibernate doesn't generate its sequence, and I cant save data from the application:
org.postgresql.util.PSQLException: ERROR: relation "hibernate_sequence" does not exist
What can I do with this?
As you didn't provide any code not sure what is wrong there, assume missing #SequenceGenerator annotation, I'll provide the one is working for me.
#Entity
#Table(name = "your_table")
#SequenceGenerator(name = "your_table_id_seq", sequenceName = "your_table_id_seq", allocationSize = 1)
public class YourTable implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "your_table_id_seq")
private Long id;
.
.
.
You need to create a sequence like this:
CREATE SEQUENCE hibernate_sequence START 1;

JPA/Ebean - force #Id to strictly increment by +1 with PostgreSQL

I have the following Model:
public class Parameter extends Model {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
}
The records created by save() look like this:
play=> select id from parameter;
id
----
1
2
3
4
5
21
(6 rows)
Is there a way that I can tell JPA to always increment the id by exactly one, instead of randomly jumping to 21?
What you are observing (jump to 21) is likely to be an implmentation detail of Ebean prior to 4.0.5. Ebean is using a 'fetch ahead' mechanism on the sequence. After 4.0.5 Ebean switched to use Postgres SERIAL by default (so by default you won't see this with Ebean/Postgres after 4.0.5). Refer: https://github.com/ebean-orm/avaje-ebeanorm/issues/97
That all said - 'incrementing EXACTLY by 1' is something you generally want to avoid as it becomes a concurrency issue (avoid making the autoincrement ID transactional as that introduces contention). When you need 'increment exactly by one' semantics (like cheque numbers etc) then you can look to create in batch in advance.
You should be able to achieve this by using #TableGenerator and allocationSize=1. An example code something like the following. You need to create a separate table to store the PK, additional work, but more portable than #GeneratedValue.
#TableGenerator(name="MAIN_PK_GEN", table="pk_gen", pkColumnName="GEN_NAME", valueColumnName="GEN_VALUE", pkColumnValue="MAIN_PK_GEN", allocationSize=1)
#Id #GeneratedValue(strategy=GenerationType.TABLE, generator="MAIN_PK_GEN" )
#Basic(optional = false)
#Column(name = "PK")
private Integer pk;
(But using allocationSize=1 may not be efficient)
See this tutorial for step by step explanation.
If you are using Oracle don't forget to add SequenceGenerator with an allocationSize of 1 :
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mysequence")
#SequenceGenerator(name = "mysequence", sequenceName = "mysequence", allocationSize = 1)
private Long id;

SQLGrammarException: ORA-00904 ("invalid identifier")

I'm getting an Oracle error / org.hibernate.exception.SQLGrammarException when I run a JUnit test against a Java class which uses JPA and Spring:
ORA-00904: "ALIAS"."COLUMN_NAME": invalid identifier
The odd thing is that the JUnit test works when run against a development database but fails when run against a database which I use for Continuous Integration builds (they are both Oracle databases).
Therefore, this would suggest that there's something missing or awry in the latter d/b. However, I have double- (and triple-)checked that the table referred to is identical in both databases and contains the column COLUMN_NAME that the error is referring to.
Further information - the DAO Java class invoked in the JUnit test uses a javax.persistence.EntityManager:
MyClass myObject = entityManager.find(MyClass.class, idNumber);
The MyClass JPA entity class maps onto the Oracle table:
#Configurable
#Entity
#Table(name = "MyTable", schema = "MySchema")
public class MyClass implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_SEQ")
#SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SEQ", allocationSize = 1)
#Column(name = "ID")
protected BigDecimal id;
#Column(name = "COLUMN_NAME")
private String columnName;
...
}
The column COLUMN_NAME in the database table in both databases is VARCHAR2(50) and nullable.
Versions:
Java - 1.6
Spring - 3.1.1
Oracle - 11.2.0.3.0
Thanks in advance for any assistance.
Found the problem. I found the query that Hibernate was creating (by adding
<property name="hibernate.show_sql" value="true" />
to my data-persistence.xml file) and tried to run it in the database where the test was failing. It transpires that in the entity Java class, the associated database table is defined like this:
#Table(name = "MyTable", schema = "MySchema")
... which works fine against the development d/b. However, the continuous integration database has all the tables created in a schema called something else, hence the error.
Thanks to everyone for their help.
Had the same issue. The reason was I missed adding the schema and the table name.
#Table(name = "Table", schema = "Schema")

GeneratedValue in Postgres

I have my entity class mapped like below:
#Entity
#Audited
#Table(name="messages_locale")
public class Locale {
#Id
#GeneratedValue
#Getter #Setter //Project Lombok's annotations, equal to generated getter and setter method
private int id;
(...)
I create clean new database ,and properties:
< prop key="hibernate.hbm2ddl.auto" >create < /prop>
WHY THE HELL (Sorry, almost two days wasted on this bug) after created database, i got a sequence in my postgres db?:
CREATE SEQUENCE hibernate_sequence
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 2
CACHE 1;
ALTER TABLE hibernate_sequence
OWNER TO postgres;
I dont want to have a sequence, I want to have just auto increment auto generated values..
I think the accepted answer from Petar is not correct, or not correct any longer. The auto-increment in Postgres is handled through SERIAL pseudo type, that’s correct. However, the mapping that Petar gives will result in the following DDL generated by Hibernate 5.1:
CREATE SEQUENCE users_id_seq START 1 INCREMENT 50;
CREATE TABLE … (
id INT8 NOT NULL,
…
);
This is not using SERIAL, but a Hibernate managed sequence. It is not owned by the table and no default value has been set. Of course, DDL generation is a feature that many people do not use in production (but many take the generated code as a template).
If you hand-write your DDL and actually used SERIAL, then using GenerationType.SEQUENCE may even conflict with the database behaviour. The correct way to map Hibernate with Postgres’ preferred ID strategy is using GenerationType.IDENTITY. Incidentally, the code is also much shorter and more readable:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
In PostgreSQL auto-increment is handled using the SERIAL pseudo type. You use this type when you execute CREATE TABLE.
Now to the point - this SERIAL pseudo type creates a sequence.
Autoincrement in PostgreSQL is handled using the created sequence. The default value of the id column becomes - nextval('your_sequence_name').
In Hibernate for an User entity:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_seq_gen")
#SequenceGenerator(name = "users_seq_gen", sequenceName = "users_id_seq")
public Long getId() {
return id;
}
Read here:
http://www.postgresql.org/docs/8.4/static/datatype-numeric.html#DATATYPE-SERIAL
http://www.neilconway.org/docs/sequences/

Categories