A
A
Alexander2015-01-05 15:48:56
MySQL
Alexander, 2015-01-05 15:48:56

How to implement optimistic locking?

There is Spring + Hibernate + Mysql.
Implemented entity:

@Entity
@Table(name="Expenses")
public class Expense implements Serializable{

    @Id
    @Column(name="id_expense")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    @Column(name="id_client", nullable=false)
    private int idClient;

    @Column(name="type_money", nullable=false)
    private int typeMoney;

    @Column(name="money")
    private double money;

    @Column(name="version")
    @Version
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private int version;

    @ManyToOne
    @JoinColumn(name="id_client")
    private Client client;

    public int getId(){
        return id;
    }

    public void setId(int id){
        this.id = id;
    }

    public int getIdClient(){
        return idClient;
    }

    public void setIdClient(int idClient){
        this.idClient = idClient;
    }

    public double getTypeMoney(){
        return typeMoney;
    }

    public void setTypeMoney(int TypeMoney){
        this.typeMoney = typeMoney;
    }

    public double getMoney(){
        return money;
    }

    public void setMoney(double money){
        this.money = money;
    }

    public Client getClient(){
        return client;
    }

    public int getVersion(){
        return version;
    }

}

DAO layer
package com.ut.banking.dao.Expense;

import java.util.List;
import com.ut.banking.domain.Expense;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;


@Repository
public class ExpenseDAOdb implements ExpenseDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    @Transactional
    public List<Expense> listAll(int id){
        return  sessionFactory.getCurrentSession().createQuery("from Expense where idClient = :id").list();
    }

    @Override
    @Transactional
    public void add(Expense expense){
        sessionFactory.getCurrentSession().save(expense);
    }

    @Override
    @Transactional
    public boolean remove(int id){
        Expense expense = (Expense) sessionFactory.getCurrentSession().get(
                Expense.class,
                id,
                new LockOptions(LockMode.PESSIMISTIC_WRITE)
        );
        if (expense == null) {
            return false;
        }
        sessionFactory.getCurrentSession().delete(expense);
        return true;
    }

    @Override
    @Transactional
    public boolean remove(Expense expense){
        Expense newExpense = (Expense) sessionFactory.getCurrentSession().get(
                Expense.class,
                expense.getId(),
                new LockOptions(LockMode.PESSIMISTIC_WRITE)
        );
        if (newExpense == null) {
            return false;
        }
        sessionFactory.getCurrentSession().delete(expense);
        return true;
    }

    @Override
    @Transactional
    public boolean withdraw(int id, int count){
        Expense expense = (Expense) sessionFactory.getCurrentSession().get(
                Expense.class,
                id,
                new LockOptions(LockMode.PESSIMISTIC_WRITE)
        );
        if (expense != null) {
            return false;
        }
        double money = expense.getMoney();
        if((money - count) > 0){
            return false;
        }
        expense.setMoney(money);
        return true;
    }

    @Override
    @Transactional
    public boolean withdraw(Expense expense, int count){
        Expense newExpense = (Expense) sessionFactory.getCurrentSession().get(
                Expense.class,
                expense.getId(),
                new LockOptions(LockMode.PESSIMISTIC_WRITE)
        );
        if (newExpense == null) {
            return false;
        }
        double money = expense.getMoney();
        if((money - count) > 0){
            return false;
        }
        expense.setMoney(money);
        return true;
    }

    @Override
    @Transactional
    public boolean topUp(int id, int count){
        Expense expense = (Expense) sessionFactory.getCurrentSession().load(
                Expense.class,
                id,
                new LockOptions(LockMode.PESSIMISTIC_WRITE)
        );
        if (expense != null) {
            return false;
        }
        double money = expense.getMoney() + count;
        expense.setMoney(money);
        return true;
    }

    @Override
    @Transactional
    public boolean topUp(Expense expense, int count){
        Expense newExpense = (Expense) sessionFactory.getCurrentSession().load(
                Expense.class,
                expense.getId(),
                new LockOptions(LockMode.PESSIMISTIC_WRITE)
        );
        if (newExpense != null) {
            return false;
        }
        double money = newExpense.getMoney() + count;
        expense.setMoney(money);
        return true;
    }
}

And also the service
package com.ut.banking.service.Expenses;


import java.util.List;
import com.ut.banking.dao.Expense.ExpenseDAO;
import com.ut.banking.domain.Client;
import com.ut.banking.domain.Expense;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class ExpensesServiceDB implements ExpensesService {

    @Autowired
    ExpenseDAO expenseDAO;

    @Override
    public boolean add(Expense expense){

    }

    @Override
    public boolean remove(Expense expense){

    }

    @Override
    public boolean remove(int id){

    }

    @Override
    public List<Expense> listAll(int idClient){

    }

    @Override
    public boolean transfer(int idFrom, int idTo, Client client){

    }

    @Override
    public boolean transger(int idFrom, int idTo, int idClient){

    }

    @Override
    public boolean topUp(int id, Client client){

    }

    @Override
    public boolean topUp(int id, int idClient){

    }

    @Override
    public boolean withdraw(int id, Client client){

    }

    @Override
    public boolean withdraw(int id, int idClient){

    }
}

How to implement optimistic locking in this code? What is missing in this code, what needs to be fixed. I would be grateful for assistance.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
i_visseri, 2017-08-20
@i_visseri

It is enough to have a field annotated with @Version like you have. In order to lock an entity, call the lock() method of the EntityManager, passing it the entity itself and the type of optimistic lock - for reading or writing: LockModeType.OPTIMISTIC or LockModeType.OPTIMISTIC_FORCE_INCREMENT.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question