So I am using Postgres and Hibernate 4.2.2 and with entity like this
#Entity(name = "Users")
#Check(constraints = "email ~* '^[A-Za-z0-9._%-]+#[A-Za-z0-9.-]+[.][A-Za-z]+$'")
#DynamicInsert
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_user",unique = true)
#Index(name = "user_pk")
private Integer idUser;
Hibernate still inserts some id that is already in the table, instead of leaving it emtpy for the database to fill it in. Also hibernate forces ids based on its cache not even checking the database whether it has the lates id.
How can I force it so I can leave id blank and let the database insert it?
First I thought it was because I was using int and that int is by default 0 but even when using object it just forces the id there from its cache.
So my goal is to let the database fill the ids instead of hibernate or at least Hibernate before filling it in to check the database for id first.
So the error I was getting wasCaused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "users_pkey" Detail: Key (id_user)=(1) already exists.
And it wasn't caused by Hibernate and caching but by import of data at creation of database, where I inserted with given ids eg: INSERT INTO users(id_user,email,password,tag) VALUES (1,'a#b.c','***','Adpleydu');
and the sequence for generating wasn't updated so if I inserted with pure SQL via console I got the same error.
Seeding the data is the problem. However you can still seed with pure sequal and have the sequence "keep up".
1) Assure your primary key is of type SERIAL.
CREATE TABLE table_name(
id SERIAL
);
2) Add this 'setval' line to assure the sequence is updated.
select setval('table_name_id_seq',COALESCE((select max(id) + 1 from table_name), 1));
Reference:
https://www.postgresqltutorial.com/postgresql-serial/
Related
I wrote program that uses different databases like sql server, oracle etc. My problem is that I can't handle GenerationType and insert correct row into table. Using GenerationType.AUTO and hibernate.id.new_generator_mappings := false in sql server, my program is able to insert new row into table, but ID is always null, same problem is when GenerationType is IDENTITY.
I tried to add auto-incrementation only for sql server, but Liquibase yells at me that it's not supported for mssql. When I use Sequences for Oracle as well SQL Server my program is trying to get "next value" from generator but it cannot and do infinite loop. Even if I set default value for ID it won't increment this value.
Thats my code :
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "name")
#SequenceGenerator(name = "name", sequenceName = "SEQ", allocationSize = 1)
private Long id;
I would like to be able to add auto-incrementing indices into table and it should work for SQL Server databases and I don't want to use Table strategy for generation because it needs additional table in db.
Problem solved. I add condition in Liquibase xml file that checks whether db is mssql type and if it's true script drops ID column and adds it with IDENTITY(1,1) option.
The only problem is that now I have to switch aforementioned "hibernate.id.new_generator_mappings" setting.
I try to prepare an integration test with test data. I read insert queries from an external file and execute them as native queries. After the insertions I execute select setval('vlan_id_seq', 2000, true );. Here is the entity ID definition:
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = IDENTITY)
private Integer id;
When I try tor persist a new entry, I got a Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "vlan_pkey"
Detail: Key (id)=(1) already exists. exception. The ID of the sequence is 2000. The column definition is done by the serial macro and is id integer NOT NULL DEFAULT nextval('vlan_id_seq'::regclass).
I executed the native queries in a user transaction, so all test entries are stored in the postgresql data base, but it seems that hibernate not sync the sequence. The entityManager.flush(); also didn't force a sequence synchronisation. It seems that hibernate did not use sequences with #GeneratedValue(strategy = IDENTITY). I use a XA-Datasource and wildfly 13.
I tested now an other initialisation method. I defined a SQL data script (I generated the script with Jailer) in the persitence.xml (javax.persistence.sql-load-script-source) and end the script with select pg_catalog.setval('vlan_id_seq', (SELECT max(id) FROM vlan), true );. I set a breakpoint before the first persist command, check the sequence in the postgresql db, the sequence has the max id value 16. Now persisting works and the entry has the id 17. The scripts are executed before the entity manager is started and hibernate read the the updated sequences while starting. But this solution did not answer my question.
Is there a possibility that hibernate reread the sequences to use the nextval value?
if the strategy is Identity this means hibernate will create a sequence table and fetch the IDs from it, by using native sql you are just inserting your own values without updating that table so you have TWO solutions
Insert using hibernate itself which will be fairly easy, in your
integration test inject your DAOs and let hibernate do the insertion
for you which is recommended so you do not need to rehandle what
hibernate already handled
Update the sequence table whenever you do the insert by increment the
value which I do not recommend.
I am new to using hibernate. I have written the following code get the max id in my order table.
public int getOrderMaxUID() {
Session session = sessionFactory.getCurrentSession();
String query = "SELECT max(o.UID) FROM Order o";
List list = session.createQuery(query).list();
int maxOrderUID = ((Integer) list.get(0)).intValue();
return maxOrderUID;
}
and I call this method in my controller before I add a new record to the table.
orderService.getOrderMaxUID();
orderService.add(o);
The Issue : Records are added to our Order table by other processes as well. So to avoid Duplicate PK issue, I get the max id from the order table before inserting record. But I still get following error when other process add records
2013-04-04 09:27:24,841 WARN ["ajp-bio-8009"-exec-2] org.hibernate.util.JDBCExceptionReporter - SQL Error: 2627, SQLState: S1000
2013-04-04 09:27:24,841 ERROR ["ajp-bio-8009"-exec-2] org.hibernate.util.JDBCExceptionReporter - Violation of PRIMARY KEY constraint 'PK_Order'. Cannot insert duplicate key in object 'Order'. The duplicate key value is (1001508).
and
org.springframework.dao.DuplicateKeyException: Hibernate flushing: could not insert:
I want hibernate to store the id retrieved by getMaxOrderId() method in memory and use the next number as when adding new record.
Any help on this would be appreciated.
Why don't you get Hibernate to just generate the ID for you?
/** The id. */
#Id #GeneratedValue
private Long id;
EDIT:
You can create entries from multiple processes as long as you do it through hibernate and the id's will be adjusted accordingly.
Inserting into the database outside of hibernate however, will cause you issues. You may be able to use a Customer ID Generator to work around this. I found this example that may help
If you edit the database outside of hibernate, you may run into other problems as well (particularly if you use the second level cache for example)
If you use the same Session, you will run into issues caused by the first level cache as well.
I am using Hibernate 4.1.0.Final with Spring 3
I have the following in Entity class
#Id
#Column(name = "PROJECT_NO")
#GeneratedValue(strategy=GenerationType.TABLE)
private String projectNumber;
Is it possible to use database trigger to populate the primary key of a table? Or I have to use a CustomGenerator for this?
When I tried the above I have the following exception
org.hibernate.id.IdentifierGenerationException: Unknown integral data type
for ids : java.lang.String
Database trigger doesn't have any sequence, it is using
SELECT NVL (MAX (project_no), 0) + 1 FROM projects
Edit 1
#GeneratedValue(generator="trig")
#GenericGenerator(name="trig", strategy="select",
parameters=#Parameter(name="key", value="projectNo"))
The above throws the following exception
Hibernate: select PROJECT_NO from PROJECTS where PROJECT_NO =?
java.lang.NullPointerException
exception in save null
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getPropertyValue(AbstractEntityTuplizer.java:645)
at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyValue(AbstractEntityPersister.java:4268)
at org.hibernate.id.SelectGenerator$SelectGeneratorDelegate.bindParameters(SelectGenerator.java:138)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:84)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2764)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3275)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
The problem is that you're using a String instead of a numeric value. Use a Long instead of a String, and your error will disappear.
AFAIK, you can't use a trigger to populate the ID. Indeed, Hibernate would have to retrieve the generated ID, but since it doesn't have an ID, I don't see how it could read back the row it has just inserted (chicken and egg problem).
You could use your SQL query to get an ID before inserting the row, but this strategy is inefficient, and has a risk of duplicate IDs in case of concurrent inserts. So I wouldn't use this strategy. You tagged your post with Oracle. I suggest you use a sequence. that's what they're for.
As of this on the Hibernate 3.3 documentation page you can do that.
select
retrieves a primary key, assigned by a database trigger, by selecting
the row by some unique key and retrieving the primary key value.
I am using DB2 for my application. I run some insertion script after creating database. That insertion script generates records in table with id's given in insertion script.
Suppose for abc table insertion script creates a record with id = 3. As id’s are set to auto generated in hibernate so while saving third record from application I got exception.
Caused by: com.ibm.websphere.ce.cm.DuplicateKeyException: One or
more values in the INSERT statement, UPDATE statement, or foreign
key update caused by a DELETE statement are not valid
because the primary key, unique constraint or unique
index identified by "1" constrains table
I am using #GeneratedValue(strategy = GenerationType.AUTO)
What strategy = GenerationType I should use to overcome this problem.
There are issues with certain Databases and Hibernate when you use GenerationType.IDENTITY. Try using a sequence and explicitlly configure everything for it:
#Id
#SequenceGenerator(name = "DEPARTMENT_ID_GENERATOR", sequenceName="department_sequence", allocationSize=100)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "DEPARTMENT_ID_GENERATOR")
#Column(unique = true, nullable = false)
protected Long id;
For DB2 #GeneratedValue(strategy = GenerationType.IDENTITY) should work correctly.
If ids are provided in file then you don't need #GeneratedValue at all as there is no id to generate. And make sure to clean database as #SjB suggested.
Also, without knowing much about DB2, the error message suggests that there may be other violation than just duplicate id on insert. Are there any foreign keys involved?
Nothing works except this query.
alter table TABLE_NAME alter column ID set GENERATED BY DEFAULT RESTART WITH 10000;
DB2 should choose available ID itself but not doing so.