danny.lesnik
danny.lesnik

Reputation: 18639

Optimistic locking and org.hibernate.StaleObjectStateException:

I'm just experimenting with Optimistic locking.

I have the following class:

@Entity
public class Student {

    private Integer id;
    private String firstName;
    private String lastName;
    private Integer version; 
@Version
    public Integer getVersion() {
        return version;
    }

//all other getters ommited.
}

now I'm fetching one of the students and try to update its properties concurrently.

Thread t1 = new Thread(new MyRunnable(id));
    Thread t2 = new Thread(new MyRunnable(id));
    t1.start();
    t2.start();

and inside of MyRunnable:

public class MyRunnable implements Runnable {
    private Integer id;
    @Override
    public void run() {
        Session session = HibernateUtil.getSessionFactory().openSession();       
        session.beginTransaction();
        Student student = (Student) session.load(Student.class, id);
        student.setFirstName("xxxx");
        session.save(student);
        session.getTransaction().commit();
        System.out.println("Done"); 
    }

    public MyRunnable(Integer id){
        this.id = id;
    }
}

what is happening that first transaction updates object successfully and second transaction throws:

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.vanilla.entity.Student#1]

This is ok.

My question is: 1) What should I do if I want second transaction to do nothing and not throw any exception.

2) What should I do if I want second transaction to override data updated by first transaction.

Thanks.

Upvotes: 8

Views: 29882

Answers (3)

srinivas konda
srinivas konda

Reputation: 11

I had the same exception. It was solved once I changed

@GeneratedValue(strategy = GenerationType.SEQUENCE)

to

@GeneratedValue(strategy = GenerationType.AUTO) 

in my entity.

My app runs on MySQL server.

Upvotes: -2

jeha
jeha

Reputation: 10750

I give a try to answer your questions:

  1. You use optimistic locking. So you want that an OptimisticLockException is thrown on version conflict - but you can catch it and do nothing. You can't switch it off for a second (whatever that means) transaction because you don't know if a version conflict will occur (this is the essence of the optimistic lock strategy: the optimistic assumption is that a version conflict won't occur very often)

  2. If an OptimisticLockException occurs, you basically have 2 options:

    1. discard the changes (and maybe refresh the current state)
    2. refresh just the version of your entity (entities) and try to commit again

    The problem is how or who is to decide which state is the actual "correct" (means latest) one if you have concurrent updates. As long as consistency is guaranteed, I wouldn't care.

Upvotes: 14

MaDa
MaDa

Reputation: 10762

Disclaimer: this is a suggestion; I haven't tried it myself.

I'd give up the version field entirely, and set this entity optimistic locking strategy to "none" in XML mapping:

<class name="Student" optimistic-lock="none"/>

or as an annotation:

@Entity(optimisticLock=OptimisticLockType.NONE)

These are Hibernate specific, you won't find them in JPA specification.

Upvotes: 0

Related Questions