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/
Related
I have code that uses Hibernate to write to an Oracle table. It uses a SequenceGenerator to generate unique id's. Say I have id's 1 through 40 in the database. What happens is that if any users are deleted from the table, it leaves a gap (say, id=24) in the id's in the table. Then, when a new user is created, the new user's id is set by Hibernate to 24.
Now there is a problem because the immediate next new user gets an id=25, which causes a UniqueConstraint exception.
Is there something I'm doing wrong? How do I make Hibernate stop generating sequence values that already exist in the table?
#Entity
#Table(name="User")
public class User {
#Id
#SequenceGenerator(name="UserGen", sequenceName="UserSeq")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="UserGen")
private Integer id;
#Column(length=64, unique=true)
private String username;
...
Here is the sequence info in Oracle:
CREATED 31-OCT-16
LAST_DDL_TIME 31-OCT-16
SEQUENCE_OWNER USERSERVICE
SEQUENCE_NAME USERSEQ
MIN_VALUE 1
MAX_VALUE 9999999999999999999999999999
INCREMENT_BY 1
CYCLE_FLAG N
ORDER_FLAG N
CACHE_SIZE 20
LAST_NUMBER 81
PARTITION_COUNT
SESSION_FLAG N
KEEP_VALUE N
You have to define your SequenceGenerator to have the same allocationSize as the INCREMENT_BY value of your sequence.
#SequenceGenerator(name="UserGen", sequenceName="UserSeq", allocationSize = 1)
I've faced this problem before (in PostgreSQL) and eventually I just changed it to #GeneratedValue( strategy = GenerationType.IDENTITY ) and removed the SequenceGenerators entirely, since they were already used as default value on insert when not specified. It's a slight performance boost when your sequence increment size is 1, because with the SequenceGenerator Hibernate calls the sequence manually, using one extra query that it can spare.
I saw this post (JPA Entity Lifecycle Events vs database trigger), but it didn't ask quite as explicitly as I am here:
Am I required to have a sequence AND a trigger for when I insert a row with a PK with a value of (null)?
Or will JPA somehow interpret the sequence annotations as a signal to grab .nextVal?
If you define a sequence on your primary key (#Id annotated field) and you map the sequence using the annotations #GeneratedValue and #SequenceGenerator, you can persist an entity with a null primary key. JPA will automatically call the sequence to get the next value (or get it from its cache).
The primary key declaration should look like.
#Id
#Column(name = "TABLE_PK")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_GENERATOR_NAME")
#SequenceGenerator(name = "SEQUENCE_GENERATOR", sequenceName = "SEQUENCE_NAME")
private Integer id;
In my web application I have multiple scheduled services which work on same entities ( like article, customer...etc). If I run a single service at time I've no problem, but when I run two services I get an error because the primary key unique constraint is violated.
As primary key I use a generated Long value:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
public Long getId() {
return id;
}
Every service read data from a txt file, create its entities and every 20 entities execute a flush on hibernate session followed by a clear. Only at the end of the execution of the service the session is committed.
How can I solve?
Oracle supports only sequences for generated keys. Add a sequence to your database:
CREATE SEQUENCE ARTICLE_SEQ;
Change your annotations to:
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="articleSequence")
#SequenceGenerator(name="articleSequence", sequenceName="ARTICLE_SEQ",allocationSize=1)
It's best to use a separate sequence for each table/type.
Create sequence in DB and use it like #GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_NAME").
I have searched on the web before posting this here, but I'm in an important project and I don't have any more time to waste with this. Well, here's the deal:
My tables in the database(SqlServer) are created automatically by Hibernate. So, I have an Entity and this entity was mapped before with Id annotation, like this:
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int id;
Hibernate created a table dbo.Parcela inside sqlServer, but we had to change the way we generate the id, Because sometimes we receive the id number and we want that id saved on our database. So our Entity now is like this:
#Id
private Integer id;
Things work fine when we run the program for the first time, but we have some customers that already have their databases created with old Id mapping and we cannot create a new table, with the new Id mapping. So when I'm trying to insert a new record I get this message:
SEVERE: Cannot insert explicit value for identity column
in table 'Parcela' when IDENTITY_INSERT is set to OFF.
Any help would be appreciate.
Thanks
So you want your surrogate keys generated by the database, except when they were already generated by the customer. How are you going to avoid collisions, if the database wants to set id=12345, but a customer-imported entry with that id already exists?
The short answer to your question is: don't do this. I don't want to go into the old natural key vs surrogate key debate, this has been done already for example here. And google "codd surrogate keys" to learn how to properly use them. All i want to say is: if you use surrogate keys, then have your database generate them, and treat everything from outside as additional lookup key. That's the sane way.
The long answer is: if you really want to do this, and if you really know what you're doing, you can implement your own IdGenerator class. In JPA for example, you could annotate your id:
#Id
#GenericGenerator(name = "customId", strategy = "com.example.CustomIdGenerator", parameters = { #Parameter(name = "sequence", value = "SEQ_IDGENERATOR") })
#GeneratedValue(generator = "customId")
#Column(name = "ID", unique = true, nullable = false)
private Integer id;
Your customIdGenerator would then extend SequenceGenerator:
public class CustomIdGenerator extends SequenceGenerator {
public Serializable generate(SessionImplementor session, Object obj) {
// return o.getId() if obj.getId() is not null
// newId = SEQ_IDGENERATOR.nextval
// while (newId is already in db) newId = SEQ_IDGENERATOR.nextval
// return newId
}
}
and your database would provide SEQ_IDGENERATOR. Id would no longer be an autogenerated field but simply
create table foo( id integer not null primary key, ...);
But again: you don't want to do this. You want your surrogate keys to be irrelevant to the outside world and handled by the database.
How did you have Hibernate create the schema for the DB? If you used hbm2ddl perhaps adding
<property name="hibernate.hbm2ddl.auto" value="update"/>
to your persistence.xml or setting hbm2ddl.auto to "update" may have Hibernate automatically update the db schema on redeploy, having it fix the insertion problem.
Of course it won't help you in cases when you try inserting an already existing id, but i guess you know it :)
We're running into an issue where we have Event subclasses that use GenerationType.TABLE to generate the primary key, and when we restart the servers we are getting duplicate primary key errors.
We're using SQL Server and Hibernate version 3.5.1-Final.
Here's what our Hibernate annotations look like:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Event {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private long eventID;
we don't specify the allocationSize so we're using the default value. The hibernate sequences table does increment but it seems like on restarts it's reusing already used ID's.
Try GenerationType.AUTO or SEQUENCE.
AUTO may work via hibernate magic, but SEQUENCE should create, funnily enough, a sequence in the database which it will use to get unique IDs.
Which SQL Server are you using?