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.
Related
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.
#Override
public Application getApplicationForId(Long applicationId) {
List<Application> applications = executeNamedQuery("applicationById", Application.class, applicationId);
return applications.isEmpty() ? null : applications.get(0);
}
while debugging in eclipse
return applications.isEmpty() ? null : applications.get(0);
these expression getting evaluated as
applications.isEmpty() -> false
applications.get(0) -> (id=171)
applications.size() -> 1
but after the execution of this line its throwing error
org.hibernate.HibernateException: More than one row with the given identifier was found: 263536,
Even its size is showing as 1, then still why and how its getting multiple rows after the execution.
I'm quite sure that this is due to eager fetching. So check you entity and remove the fetch=FetchType.EAGER.
Actually this is not caused by duplicate rows in the database, as it's obviously not possible to have duplicate primary keys. Instead this was caused by Hibernate looking up an object, and eagerly filling in a relationship. Hibernate assumed a single row would come back, but two came back because there were two objects associated with that relationship.
In my case the issue was,
while debugging when the execution is in the middle of the transaction, may be the purpose got served and forcibly stopped the server in the middle of the execution itself, as this has been forcibly stopped server, that cannot led the transaction to get rolledback and that end up in making the data dirty or corrupt in the database because before terminating the server some data might got inserted in db (chance of autoincrement of the primarykey).
Resetting the AutoIncrement value for the primary key of the table, resolved the issue.
1.Identify the table with dirty data (refer to stack trace )
2.Sort the column(primary key), check the highest value in the column(say somevalue).
3.use command
ALTER TABLE tablename AUTO_INCREMENT = somevalue+1
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/
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 Hibernate and getting
Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [#271]
What is pretty weird about this error is, that the object with the given id exists in the database. I inserted the problematic record in another run of the application. If I access it in the same run (i.e. same hibernate session) there seem to be no problems retrieving the data.
Just because it could be a fault of the mapping:
public class ProblemClass implements Persistent {
#ManyToOne(optional = false)
private MyDbObject myDbObject;
}
public class MyDbObject implements Persistent {
#OneToMany(mappedBy = "myDbObject")
private List<ProblemClass> problemClasses;
#ManyToOne(optional = false)
private ThirdClass thirdClass;
}
I have absolutely no clue even where to look at. Any hints highly appreciated!
Just to clarify:
The data was inserted in another RUN of the application. It is definitely in the database, as I can see it via an SQL-Query after the application terminated. And after THAT, i.e. when starting the application again, I get the error in the FIRST query of the database -- no deletion, no rollback involved.
Addition:
Because it was asked, here is the code to fetch the data:
public List<ProblemClass> getProblemClasses() {
Query query = session.createQuery("from ProblemClass");
return query.list();
}
And just to make it complete, here is the generic code to insert it (before fetching in another RUN of the application):
public void save(Persistent persistent) {
session.saveOrUpdate(persistent);
}
Eureka, I found it!
The problem was the following:
The data in the table ThirdClass was not persisted correctly. Since this data was referenced from MyDbObject via
optional = false
Hibernate made an inner join, thus returning an empty result for the join. Because the data was there if executed in one session (in the cache I guess), that made no problems.
MySQL does not enforce foreign key integrity, thus not complaining upon insertion of corrupt data.
Solution: optional = true or correct insertion of the data.
Possible reasons:
The row was inserted by the first session, but transaction was not committed when second session tried to access it.
First session is roll-backed due to some reason.
Sounds like your transaction inserting is rollbacked
Main reason behind this issue is data mismatch, for example i have entity mapping class called "X" and it has column "column1" and it has reference to the table "Y" column "column1" as below
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "column1", referencedColumnName = "column1")
public Y getColumn1() {
return Y;
}
In this if X table column1 has value but Y table column1 is not having the value. Here link will be failed.
This is the reason we will get Hibernate objectNotFound exception
This issue can also be resolved by creating proper data model like creating proper indexing and constraints (primary key/foreign key) ..
This might be your case, kindly check my answer on another post.
https://stackoverflow.com/a/40513787/6234057
I had the same Hibernate exception.
After debugging for sometime, i realized that the issue is caused by the Orphan child records.
As many are complaining, when they search the record it exists.
What i realized is that the issue is not because of the existence of the record but hibernate not finding it in the table, rather it is due to the Orphan child records.
The records which have reference to the non-existing parents!
What i did is, find the Foreign Key references corresponding to the Table linked to the Bean.
To find foreign key references in SQL developer
1.Save the below XML code into a file (fk_reference.xml)
<items>
<item type="editor" node="TableNode" vertical="true">
<title><![CDATA[FK References]]></title>
<query>
<sql>
<![CDATA[select a.owner,
a.table_name,
a.constraint_name,
a.status
from all_constraints a
where a.constraint_type = 'R'
and exists(
select 1
from all_constraints
where constraint_name=a.r_constraint_name
and constraint_type in ('P', 'U')
and table_name = :OBJECT_NAME
and owner = :OBJECT_OWNER)
order by table_name, constraint_name]]>
</sql>
</query>
</item>
2.Add the USER DEFINED extension to SQL Developer
Tools > Preferences
Database > User Defined Extensions
Click "Add Row" button
In Type choose "EDITOR", Location - where you saved the xml file above
Click "Ok" then restart SQL Developer
3.Navigate to any table and you will be able to see an additional tab next to SQL, labelled FK References, displaying FK information.
4.Reference
http://www.oracle.com/technetwork/issue-archive/2007/07-jul/o47sql-086233.html
How can I find which tables reference a given table in Oracle SQL Developer?
To find the Orphan records in all referred tables
select * from CHILD_TABLE
where FOREIGNKEY not in (select PRIMARYKEY from PARENT_TABLE);
Delete these Orphan records, Commit the changes and restart the server if required.
This solved my exception. You may try the same.
Please update your hibernate configuration file as given below:
property start tag name="hbm2ddl.auto" create/update property close tag
I have found that in Oracle this problem can also be caused by a permissions issue. The ProblemClass instance referred to by the MyDbObject instance may exist but have permissions that do not allow the current user to see it, even though the user can see the current MyDbObject.