Как реализовать оптиместическую блокировку?

Имеется Spring + Hibernate + Mysql.
Реализованна сущность:
@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;
    }

}


Слой ДАО
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;
    }
}


А также сервис
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){

    }
}


Как в данном коде реализовать оптиместическую блокировку? Чего в этом коде не хватает, что необходимо исправить. Буду признателен в случаее содействия.
  • Вопрос задан
  • 2512 просмотров
Пригласить эксперта
Ответы на вопрос 1
@i_visseri
Достаточно завести поле, аннотированное @Version как у вас. Для того, чтобы наложить блокировку на сущность вызовите метод lock() у EntityManager'a, передав ему саму сущность и тип оптимистической блокировки - на чтение или запись: LockModeType.OPTIMISTIC или LockModeType.OPTIMISTIC_FORCE_INCREMENT.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы