It turns out that the following example works when using mysql 5.x, however it doesn't when using an oracle 10g database.
Is there a way to define a unique identifier field that is independent of the database technology?
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private long id;
I have tested this in hibernate and the following exception occurs only when using Oracle:
org.hibernate.MappingException: Dialect does not support identity key generation
Using a database table is a portable way to generate identifiers.
The simplest way to use a table to generate identifiers is to specify TABLE as the generation strategy:
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
#Column(name="id")
private long id;
The provider will create the default table if you're using schema generation; if not, you must specify an existing table:
#TableGenerator(name="InvTab",
table="ID_GEN",
pkColumnName="ID_NAME",
valueColumnName="ID_VAL",
pkColumnValue="INV_GEN")
#Id
#GeneratedValue(generator="InvTab")
#Column(name="id")
private long id;
http://www.oracle.com/technology/products/ias/toplink/jpa/howto/id-generation.html#table
I have researched using GenerationType.AUTO and it does appear to be the better option. It allows the JPA implementation to choose whatever is best for the data storage system you are using.
Related
We have a Java program using Hibernate 5 that can be installed using different DB Engines: Oracle, PostgreSQL or SQL Server. Now we are introducing MySql.
The entities have a Generated Value AUTO identifier.
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
This worked fine until now. Oracle and PostgreSQL installations are using HIBERNATE_SEQUENCE sequence to generate the id values and SQL Server is using a table generated id (IDENTITY).
With MySQL we would like to use also the table generated id, but Hibernate 5 GenerationType.AUTO on MySQL tries the TABLE generator instead of the IDENTITY generator.
I found this solution by Vlad Mihalcea where using a native generator makes Hibernate to select IDENTITY for MySQL:
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
protected Long id;
That's nice for MySQL, but then the application is no longer working in Oracle (ORA-02289: sequence does not exist). I think Hibernate is then searching for a sequence called native in the Oracle DB.
Is there a solution to keep the ID generation the same for all the other DB engines (Oracle, PostgreSQL and SQL Server) and use the IDENTITY for MySQL?
If not the only solution I can see is to implement the TABLE ID generation in MySQL, but it seems not to have a good performance.
I almost had it in the question, but in case somebody falls in the same situation: calling the generator HIBERNATE_SEQUENCE will make it backwards compatible with Oracle and PostgreSQL (SQL Server will continue using IDENTITY).
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "HIBERNATE_SEQUENCE")
#GenericGenerator(name = "HIBERNATE_SEQUENCE", strategy = "native")
protected Long id;
Hey this question/answer got me on the road to the answer. I am using Hibernate core 5.4.30 with MSSQL SQLServer2012Dialect and Oracle Oracle12cDialect. I needed to use the #GenericGenerator annotation as well for it's native strategy. maybe I could have used this directly with #GeneratedValue? anyway...
I found Oracle did not come with a sequence named HIBERNATE_SEQUENCE, and even when I added one, hibernate was still giving me sequence not found errors, seemingly having to do with my schema... So you can make things more specific like this:
#Id
#GenericGenerator(name = "MY_SEQUENCE", strategy = "native",
parameters = {
#org.hibernate.annotations.Parameter(name = "schema", value="MY_SCHEMA"),
#org.hibernate.annotations.Parameter(name = "sequence_name", value="MY_SEQUENCE")
}
)
#GeneratedValue(generator = "MY_SEQUENCE")
private Long id;
Hypothetically the name of the #GenericGenerator only has to match the generator name in the #GeneratedValue, but I made it the same as my actual database sequence for simplicity.
Within JPA in Spring Boot / Spring Data, I want to set up an entity class.
The business requirement is to historize the processing of documents that exist once per year each.
The processing is performed in a bulk: so all documents are processed together: there is one processingTimestamp for all documents in the database for each processing sequence.
Later on, I want to access only the most recently processed document, but keep the previously processed documents for reference.
I see the following alternatives:
Use a composite key
#Id
private String documentId;
#Id
private String yearOfDocumentCreation;
#Id
private java.sql.Timestamp processingTimestamp;
Use an auto generated key
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String documentId;
private String yearOfDocumentCreation
private java.sql.Timestamp processingTimestamp;
Which alternative is better/best practise regarding
Handling (e.g. storing a list of documents as a bulk that were read before from the database and avoiding duplicates in the database)
Performance
Or do I miss other alternatives/aspects?
I recommend using a single Long primary key, if you will need to make a foreign key to this table.
To avoid dublicates you can make a unique constraint on the 3 required columns.
I am trying to have separate auto incremented id generator for each of my entities.
The target database is a SQL Server database, and I am using Hibernate 5.2.4.Final. Also I am generating the tables from code.
I have an abstract BaseEntity and other child entities like below, and thus, I am aiming for TABLE_PER_CLASS.
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity {
protected long id;
#Id
#GeneratedValue(strategy = GenerationType.XXX)
#Column(name = "Id")
public long getId() {
return id;
}
}
#Entity
#Table(name = "Tags")
public class Tag extends BaseEntity {
}
Below are the different scenarios that I have faced so far:
setting XXX to AUTO: Creates a hibernate_sequence table in database, which I assume, will not provide separate id sequence for separate table.
setting XXX to SEQUENCE: Same as above. Referred this, while doing it.
setting XXX to TABLE: Creates a hibernate_sequences table, which can provide separate id sequence for separate table. However, I have found out that this is quite expensive (same reference as above), and also not my preferred strategy.
setting XXX to TABLE: Does not work for TABLE_PER_CLASS.
What I actually want to use is the native identity column of SQL Server. However, using the SEQUENCE is also an option, but I am not sure how to create and use one for each table from hibernate. Please suggest how either one of these two can be achieved.
Update on the answer by Khalil M. I tried it in 2 possible ways:
applying on BaseEntity -> does not create a separate sequence for each table, and rather creates a ID_SEQNCE, which queried before saving every new entity. So, I am not sure how this is any different than using GenerationType.TABLE.
applying it on each individual entity class -> while saving, the generator creates duplicate id.
for creating a sequence use this
#Id
#GeneratedValue(generator = "ID_SEQ", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "ID_SEQ", sequenceName = "ID_SEQNCE",allocationSize=1)
Edit:
You have to make it by yourself because what you are asking is not supported in Table per class
the id has to be shared across several tables. Consequently, when
using this strategy, you should not use AUTO nor IDENTITY.
for more info
Use strategy = GenerationType.IDENTITY
A short example is below
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
The GenerationType.IDENTITY is the easiest to use but not the best one from a performance point of view. It relies on an auto-incremented database column and lets the database generate a new value with each insert operation. From a database point of view, this is very efficient because the auto-increment columns are highly optimized, and it doesn’t require any additional statements.
I'm trying to use a defined sequence generation in Oracle JPA, along with GenerationType.AUTO like this:
#Id
#SequenceGenerator(name = "MY_GEN_NAME", sequenceName = "MY_SQ_NAME")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "MY_GEN_NAME")
#Column(name = "ID", nullable = false)
private Long id;
After running the hibernate validation it throws an error:
Schema validation: missing sequence [hibernate_sequence]
I guess, it is ignoring my MY_GEN_NAME and trying to use that global sequence for id generation.
When I switch to GenerationType.SEQUENCE, it uses SequenceHiLoGenerator and it works fine.
Why is that happening, and is it possible to make the GenerationType.AUTO work with given sequence for Oracle (possibility to switch to other db)?
AUTO says to the JPA provider, "choose what you want", and it will not use the "generator" attribute in that case.
If you want to use a SEQUENCE then set the strategy to SEQUENCE! That way it will use the sequence definition you have defined
Though hibernate-sequence-on-oracle-generatedvaluestrategy-generationtype-auto suggests that this will work, it appears that it is broken for some versions of Hibernate, see HHH-10656.
Edit: Broken in 5.2.0, unbroken in 5.2.8.
I have an entity which has an ID field:
#Id
#Column(name = "`U##ID_VOIE`")
#GeneratedValue(generator = "VOIE_SEQ")
private String id;
The class has the sequence generator defined as well:
#SequenceGenerator(name = "VOIE_SEQ", sequenceName = "VOIE_SEQ")
and the Oracle schema has the requisite sequence present. Everything works okay.
We also have tests, which uses an in-memory HSQLDB. Before running the tests, all the tables are created based on the Hibernate entity classes.
However the table for this particular class is not being created. And error pops up, because ID is a String and the SequenceGenerator in HSQLDB returns an INT / LONG / Numeric value.
The application is using a legacy Oracle database and ID_VOIE column must remain a String / Varchar.
Any solutions?
Using H2 instead.