org.hibernate.HibernateException: identifier of an instance
of org.cometd.hibernate.User altered from 12 to 3
in fact, my user table is really must dynamically change its value, my Java app is multithreaded.
Any ideas how to fix it?
Are you changing the primary key value of a User object somewhere? You shouldn't do that. Check that your mapping for the primary key is correct.
What does your mapping XML file or mapping annotations look like?
You must detach your entity from session before modifying its ID fields
In my case, the PK Field in hbm.xml was of type "integer" but in bean code it was long.
In my case getters and setter names were different from Variable name.
private Long stockId;
public Long getStockID() {
return stockId;
}
public void setStockID(Long stockID) {
this.stockId = stockID;
}
where it should be
public Long getStockId() {
return stockId;
}
public void setStockId(Long stockID) {
this.stockId = stockID;
}
In my case, I solved it changing the #Id field type from long to Long.
In my particular case, this was caused by a method in my service implementation that needed the spring #Transactional(readOnly = true) annotation. Once I added that, the issue was resolved. Unusual though, it was just a select statement.
Make sure you aren't trying to use the same User object more than once while changing the ID. In other words, if you were doing something in a batch type operation:
User user = new User(); // Using the same one over and over, won't work
List<Customer> customers = fetchCustomersFromSomeService();
for(Customer customer : customers) {
// User user = new User(); <-- This would work, you get a new one each time
user.setId(customer.getId());
user.setName(customer.getName());
saveUserToDB(user);
}
In my case, a template had a typo so instead of checking for equivalency (==) it was using an assignment equals (=).
So I changed the template logic from:
if (user1.id = user2.id) ...
to
if (user1.id == user2.id) ...
and now everything is fine. So, check your views as well!
It is a problem in your update method. Just instance new User before you save changes and you will be fine. If you use mapping between DTO and Entity class, than do this before mapping.
I had this error also. I had User Object, trying to change his Location, Location was FK in User table. I solved this problem with
#Transactional
public void update(User input) throws Exception {
User userDB = userRepository.findById(input.getUserId()).orElse(null);
userDB.setLocation(new Location());
userMapper.updateEntityFromDto(input, userDB);
User user= userRepository.save(userDB);
}
Also ran into this error message, but the root cause was of a different flavor from those referenced in the other answers here.
Generic answer:
Make sure that once hibernate loads an entity, no code changes the primary key value in that object in any way. When hibernate flushes all changes back to the database, it throws this exception because the primary key changed. If you don't do it explicitly, look for places where this may happen unintentionally, perhaps on related entities that only have LAZY loading configured.
In my case, I am using a mapping framework (MapStruct) to update an entity. In the process, also other referenced entities were being updates as mapping frameworks tend to do that by default. I was later replacing the original entity with new one (in DB terms, changed the value of the foreign key to reference a different row in the related table), the primary key of the previously-referenced entity was already updated, and hibernate attempted to persist this update on flush.
I was facing this issue, too.
The target table is a relation table, wiring two IDs from different tables. I have a UNIQUE constraint on the value combination, replacing the PK.
When updating one of the values of a tuple, this error occured.
This is how the table looks like (MySQL):
CREATE TABLE my_relation_table (
mrt_left_id BIGINT NOT NULL,
mrt_right_id BIGINT NOT NULL,
UNIQUE KEY uix_my_relation_table (mrt_left_id, mrt_right_id),
FOREIGN KEY (mrt_left_id)
REFERENCES left_table(lef_id),
FOREIGN KEY (mrt_right_id)
REFERENCES right_table(rig_id)
);
The Entity class for the RelationWithUnique entity looks basically like this:
#Entity
#IdClass(RelationWithUnique.class)
#Table(name = "my_relation_table")
public class RelationWithUnique implements Serializable {
...
#Id
#ManyToOne
#JoinColumn(name = "mrt_left_id", referencedColumnName = "left_table.lef_id")
private LeftTableEntity leftId;
#Id
#ManyToOne
#JoinColumn(name = "mrt_right_id", referencedColumnName = "right_table.rig_id")
private RightTableEntity rightId;
...
I fixed it by
// usually, we need to detach the object as we are updating the PK
// (rightId being part of the UNIQUE constraint) => PK
// but this would produce a duplicate entry,
// therefore, we simply delete the old tuple and add the new one
final RelationWithUnique newRelation = new RelationWithUnique();
newRelation.setLeftId(oldRelation.getLeftId());
newRelation.setRightId(rightId); // here, the value is updated actually
entityManager.remove(oldRelation);
entityManager.persist(newRelation);
Thanks a lot for the hint of the PK, I just missed it.
Problem can be also in different types of object's PK ("User" in your case) and type you ask hibernate to get session.get(type, id);.
In my case error was identifier of an instance of <skipped> was altered from 16 to 32.
Object's PK type was Integer, hibernate was asked for Long type.
In my case it was because the property was long on object but int in the mapping xml, this exception should be clearer
If you are using Spring MVC or Spring Boot try to avoid:
#ModelAttribute("user") in one controoler, and in other controller
model.addAttribute("user", userRepository.findOne(someId);
This situation can produce such error.
This is an old question, but I'm going to add the fix for my particular issue (Spring Boot, JPA using Hibernate, SQL Server 2014) since it doesn't exactly match the other answers included here:
I had a foreign key, e.g. my_id = '12345', but the value in the referenced column was my_id = '12345 '. It had an extra space at the end which hibernate didn't like. I removed the space, fixed the part of my code that was allowing this extra space, and everything works fine.
Faced the same Issue.
I had an assosciation between 2 beans. In bean A I had defined the variable type as Integer and in bean B I had defined the same variable as Long.
I changed both of them to Integer. This solved my issue.
I solve this by instancing a new instance of depending Object. For an example
instanceA.setInstanceB(new InstanceB());
instanceA.setInstanceB(YOUR NEW VALUE);
In my case I had a primary key in the database that had an accent, but in other table its foreign key didn't have. For some reason, MySQL allowed this.
It looks like you have changed identifier of an instance
of org.cometd.hibernate.User object menaged by JPA entity context.
In this case create the new User entity object with appropriate id. And set it instead of the original User object.
Did you using multiple Transaction managers from the same service class.
Like, if your project has two or more transaction configurations.
If true,
then at first separate them.
I got the issue when i tried fetching an existing DB entity, modified few fields and executed
session.save(entity)
instead of
session.merge(entity)
Since it is existing in the DB, when we should merge() instead of save()
you may be modified primary key of fetched entity and then trying to save with a same transaction to create new record from existing.
How can I update every fields in Entity without write sql query:
(update Entity u set u.m1= ?1, u.m2= ?2, ... where u.id = ?3)
Class has 20+ fields and if I write sql query This will take a long time. And I often add new fields
Can I update everything automatically? Like this:
entityRepo.update(entity);
If i do entityRepo.save(); create unnecessary record in base.
No, you can use JpaRepository.save(S entity) that saves or updates the entity if existing.
To achieve that, make sure that the entity has its JPA #Id valued before invoking save() otherwise a new record will indeed be created.
This is an alternative to #davidxxx's answer.
If the transaction with which the entity was fetched is not yet closed (i.e. the entity is still attached), you can simply update the java-object and the changes will be committed to the database when the transaction is committed.
I know that save() will insert my object if its not already present in db and will go for update if its already present (object identified using the primary key field).
I have tried a code as follows
public void update() throws UpdateFailedException{
boolean b= findByPK(); // checking if the entry is already present.
if(b){
repo.save(object); // saving it, internally it will be updating.
}else{
throw new UpdateFailedException("Object not present to update");
}
}
The above code will not meet my efficiency requirements as its polling my db a number of times and further I cannot guarantee the consistency in its behavior since its not happening in the same transaction boundary.(ie even if I get that the record already exists in db, there is a possibility for my record to be removed from external boundary before calling the save and as a result my save will do an insert which I want to prevent)
What will be an efficient way to do this ? I also need to manage the transaction for the spring data JPA.
or Is there any way by which I can know if the save() is doing an insert or not ? (so that I can prevent calling save() if its going to do an insert)
Let's say you have 10 properties and the user has just changed one property so instead of updating all the 10 properties you can use #DynamicUpdate. This will only update the changed fields.
Hibernate 4+
#DynamicInsert(true)
#DynamicUpdate(true)
#Entity
#Table(name = "User")
#org.hibernate.annotations.Entity(dynamicUpdate = true) //may be deprecated
public class User
The #DynamicUpdate is used to specify that the UPDATE SQL statement should be generated whenever an entity is modified. By default, Hibernate uses a cached UPDATE statement that sets all table columns. When the entity is annotated with the #DynamicUpdate annotation, the PreparedStatement is going to include only the columns whose values have been changed.
I supose you set Id to 0 when the object does not exist in your DB so if it´s and updated object it should have an Id != 0
public void update() throws UpdateFailedException{
if(object.getId() != 0){
repo.save(object); // saving it, internally it will be updating.
}else{
throw new UpdateFailedException("Object not present to update");
}
}
I'm working in a project right now, here is a piece of code:
public boolean getAll() {
TypedQuery<Tag> query = em.createQuery("SELECT c FROM Tag c WHERE (c.tagName !=?1 AND c.tagName !=?2 AND c.tagName !=?3) ", Tag.class);
query.setParameter(1, "Complete");
query.setParameter(2, "GroupA");
query.setParameter(3, "GroupB");
List<Tag> Tag= query.getResultList();
But when I try to do something like this:
Tag.get(2).setTagName = "Hello";
em.persist(Tag.get(2));
It considers it to be an update instead of a create? How can I make JPA understand that it's not database related, to detach the chains with the Database and create new register only changing its name for example?
Thanks a lot for any help!
Best regards!
EDIT:
Using the em.detach just before changing it values and persisting each of the list worked just fine!
Thanks everyone!
You haven't showed us how you are obtaining your list, but there are two key points here:
everything read in from an EntityManager is managed - JPA checks
these managed objects for changes and will synchronize them with the
database when required (either by committing the transaction or
calling flush).
Calling persist on a managed entity is a no-op - the entity is
already managed, and will be synchronized with the database if it
isn't in there yet.
So the first Tag.get(2).setTagName = "Hello"; call is what causes your update, while the persist is a no-op.
What you need do to instead is create a new instance of your tag object and set the field. Create a clone method on your object that copies everything but the ID field, and then call persist on the result to get an insert for a new Entity.
The decision whether to update or create a new entity object is done based on the primary key. You're probably using an ID on every object. Change or remove it and persist then. This should create a new entry.
If that doesn't work, you might need to detach the object from the Entity Manager first:
em.detach(tagObj);
and persist it afterwards:
em.persist(tagObj);
You can also force an update instead of creation by using
em.merge(tagObj)
There is no equivalent for forced creation AFAIK. persist will do both depending on PK.
I have a object A which maps to table A in DB
class A {
Integer id;
String field2,field2;field3 ,... fieldN;
//lots of other attribute
}
Now i want to write a DAO api that just updates a single field.One approach is that i can first load the object then changes the attribute i need and then use merge api
//start transcation
A a = session.load(A.class, id);
A.setfieldP(newValue)
session.merge(A)
//commit transcation
Now if i use following code
//start transcation
A a = new A();
a.setId(id); //set a id by which object A exists in DB
A.setfieldP(newValue)
session.merge(A)
//commit transaction
Now second approach all fields except id and fieldP are set to null
1)Now is there any other approach?
2)Can i use update instead of merge ?
If you need to update lots of entities at once the most efficient way is to use a query:
Query query = session.createQuery("update EntityName set fieldP = 'newValue' "
+ "where id IN (75, 76)");
query.executeUpdate();
This allows you to change field values without loading the entity or entities into memory.
It is best practice is to use named queries and named parameters - the above implementation is just an example.
I usually prefer session.get vs session.load, as session.get will return null as opposed to throwing an exception, but it depends on the behavior you want.
loading the object, setting your field, and calling either
session.merge(myObject)
is the standard way, although you can also use
session.saveOrUpdate(myObject)
as long as the object hasn't been detached, which in your case, it won't have been detached. Here is a good article explaining the differences in merge and saveOrUpdate.
In your second example, you are editing the primary key of the object? This is generally bad form, you should delete and insert instead of changing the primary key.
Using JPA you can do it this way.
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaUpdate<User> criteria = builder.createCriteriaUpdate(User.class);
Root<User> root = criteria.from(User.class);
criteria.set(root.get("fname"), user.getName());
criteria.set(root.get("lname"), user.getlastName());
criteria.where(builder.equal(root.get("id"), user.getId()));
session.createQuery(criteria).executeUpdate();
One more optimization here could be using dynamic-update set to true for the entity. This will make sure that whenever there is an update, only field(s) which are changed only gets updated.