Problem with HSQLDB & SequenceGenerator - java

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.

Related

Hibernate 5 ID AUTO Generation Type for Oracle as Sequence and MySQL as Identity

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.

How to generate auto incremented id for each table separately using SQL Server and Hibernate

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.

How can I force positive auto generated hibernate primary keys

I am using JPA 2.1 with Hibernate 4.3.8. on Oracle, MySQL, PostgreSQL and MS SQL. For creating numeric primary keys I have used the following code :
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "t_gen")
#SequenceGenerator(name = "t_gen", sequenceName = "T_SEQ")
private long id;
So far so good. But I need to generate only positive values of IDs under all conditions. How can I force Hibernate to generate only positive ID's on each database (MS SQL, MySQL, PostgreSQL, Oracle) ?
Hope this helps;
If allocationSize is not declared on the entity side, as default allocation size is 50 ALL sequences MUST declare INCREMENT BY 50 on the DB side.
Reference Link:
http://skay-dev.blogspot.in/2013/09/hibernate-sequence-and-negative.html

Hibernate JPA Column "NEXTVAL" not found

We changed the JPA provider from EclipseLink to Hibernate 4.1.3. A problem occured when attempting to persist entity using generated id. This gives the following error:
JdbcSQLException: Column "NEXTVAL" not found; SQL statement: select nextval for SCHEMA.ID_SEQ_GENERATOR
The sequence for the entity looks like the following:
#Id
#SequenceGenerator(name = "ID_GENERATOR", initialValue = 100000, allocationSize = 1, sequenceName = "ID_SEQ_GENERATOR")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ID_GENERATOR")
#Column(name = "ID", nullable = false)
public Long getId() {
return this.id;
}
I tried changing the 'strategy = GenerationType.IDENTITY', but it had no effect.
Any advice?
I found out that there are different databases used depending on the environment used. The dialect used is (currently) always the same even though it should change depending on the server the code is executed on. (The correct dialect is actually loaded first, but it then gets replaced because of spring decides to use another class annotated with #Configuration. I think that using profiles should get me past this, though still working with this...)
I found this link which helped me to get on right tracks:
http://techmagik.blogspot.fi/2012/07/sequence-support-in-jpa-for-db2-zos.html.html
Discovering that the H2 was used, I changed the SQL to :
"NEXT VALUE FOR " + sequenceName
Which fixed the error
So the actual problem is with loading correct dialect (as 'Luca Basso Ricci' hinted). The dialect is for DB2 (always), when it should be for H2 in some cases. For some reason this problem manifested when the provider was changed so it made it a bit difficult to track right reason.

JPA GenerationType.AUTO not considering column with auto increment

I have a table with a simple int id column with Identity auto increment in SQL Server.
The entity's Id is annotated with #Id and #GeneratedValue
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
In SQL Server the column is properly set as Identity with Seed and Increment equals to 1.
When I try to persist an instance of this entity, Hibernate tries to query the hibernate_sequence table to obtain the ID value. Since I haven't created that table in my schema I'm getting an error:
could not read a hi value: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid object name 'MySchema.hibernate_sequence'
If I change the generation type to IDENTITY everything works as expected
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
I cannot change it this way, since my App will run both on MS SQL and ORACLE, and the latter does not support auto incremented columns.
As far as I know the AUTO type should use the auto increment behaviour if the underlying database has support to it, so I don't know why is not working.
UPDATE:
It took me some time but I was able to understand exactly what is going on.
I am working with legacy databases with the following behaviours:
MSSQL: id generation uses table IDENTITY
ORACLE: id generation uses a trigger. The trigger queries and updates a custom table where all the "next ids" are stored. This table is called SEQ.
Here is the outcome of using some id generation strategies:
AUTO: does not work in MSSQL, as explained above
IDENTITY: works in MSSQL but is not supported by Oracle
"native": works in MSSQL but fails in ORACLE. It fails because Hibernate activates its default sequence strategy, which uses hibernate_sequences.nextval. Since this is a legacy application the values from the SEQ table (mentioned above) and the hibernate_sequences are not synchronized (SEQ's value for that particular table is at 6120, and hibernate_sequences' is at 1, which is expected since it was not used until now).
So what I need to figure out is a way to configure that entity to:
Use MSSQL Identity feature
OR
When using Oracle, do not automatically set any value to the ID variable and leave everything up to the pre-existing trigger
This can cause me serious issues on Oracle when I need to insert entities that depend on the main entity (via foreign key), because Hibernate won't know which ID value was generated by the "external" trigger.
I had a similar problem and found this information (deeper explained in here).
Adding this property into my persistence.xml file fixed the issue:
<property name="hibernate.id.new_generator_mappings" value="false" />
Orcale 12c supports IDENTITY and SQL SERVER 2012 supports SEQUENCES. I believe a SEQUENCE is always a better choice than an IDENTITY. IDENTITY disables batching and SEQUENCES allow you to provide optimizers, such as the pooled-lo optimization strategy.
This is how the actual identifier generator is chosen for the configured GenerationType value:
switch ( generatorEnum ) {
case IDENTITY:
return "identity";
case AUTO:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "native";
case TABLE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.TableGenerator.class.getName()
: MultipleHiLoPerTableGenerator.class.getName();
case SEQUENCE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "seqhilo";
}
If you use the new identifier generators:
properties.put("hibernate.id.new_generator_mappings", "true");
The AUTO will actually use a SequenceStyleGenerator and where the database doesn't support sequences, you end up using a TABLE generator instead (which is a portable solution but it's less efficient than IDENTITY or SEQUENCE).
If you use the legacy identifier generators, you then end up with the "native" generation strategy, meaning:
public Class getNativeIdentifierGeneratorClass() {
if ( supportsIdentityColumns() ) {
return IdentityGenerator.class;
}
else if ( supportsSequences() ) {
return SequenceGenerator.class;
}
else {
return TableHiLoGenerator.class;
}
}
If a new Oracle12gDialect is going to be added and it will support IDENTITY, then AUTO might switch to IDENTITY rather than SEQUENCE, possibly breaking your current expectations. Currently there is no such dialect available so on Oracle you have SEQUENCE and in MSSQL you have IDENTITY.
Conclusion:
Try it like this:
#Id
#GenericGenerator(name = "native_generator", strategy = "native")
#GeneratedValue(generator = "native_generator")
private Long id;
make the id a Long instead of Integer, and you can let the HBMDDL handle the primary key column type.
force Hibernate to use the "native" generator
If your legacy system uses a table for generating sequence values and there was no hilo optimization ever used you can use a table identifier generator:
#Id
#GeneratedValue(generator = "table", strategy=GenerationType.TABLE)
#TableGenerator(name = "table", allocationSize = 1
)
private Long id;
You can also use the JPA table generator, just make sure you configure the right optimizer. For more info check my Hibernate tutorial
because
#GeneratedValue(strategy = GenerationType.AUTO)
use SequenceStyleGenerator by default in earlier versions
you have to look at this https://hibernate.atlassian.net/browse/HHH-11014

Categories

Resources