2013-02-13 3 views
4

я реализовал услугу для entity object и использует чистый jpa, я использовал spring, поэтому в spring xml config настроен hibernate как jpa осущ. Я использую spring данных для crud операций. Но в нашей системе находится наш entity объект вытащил/обновил много раз, и есть высокая конкуренция (concurrency). Из нашего кода во многих местах много classes только inject сервисный компонент и вызов метода getEntity для получения сущности, после него они меняют сущность (которая отделяется как мое понимание, но в том же потоке, поэтому объект em должен быть таким же, как в мои знания), поэтому требуется некоторое время, когда объект возвращается к обновляемому сервису, они вызывают метод службы save() для сохранения объекта. Save() метод - это всего лишь звонки merge() crud operation. это транзакция с аннотацией @Transactional. Здесь возникает проблема, когда кто-то тянет объект сущности, и, изменяя его, кто-то другой может потянуть и изменить его и сохранить его обратно, поэтому мой сущность прочитана, и если сохранить ее, я переопределю уже обновленный объект. Проблема заключается в том, что мы меняем сущность вне службы и вызываем ее обратно. Здесь весовые классы хранилищ данных - это слой DAO.JPA слияния() лучшая практика

Optimistic lock - одно решение, но по некоторым причинам нам это не понравилось, поэтому оно не работает для нас. Я думаю о pessimistic lock. Например, когда я получаю сущность для обновления путем блокировки, затем меняю ее где-то в другом месте и перезвоняю (entity уже заблокирован от обновления!) Работает ли она? Я не уверен, есть ли еще объект EntityManager, который я использовал для вытягивания объекта. Если это так, требуется пройти довольно много времени, чтобы передать эти «умные» логики, прежде чем они будут обновлены и разблокируются.

Вот простой пример код для сценария:

class SomeEntity { 
    Long id; 
    String field1; 
    String field2; 
    String field3; 
    String field4; 
    String field5; 
    String field6; 
    String field7; 
    //getters and setters, column annotations 

} 


class SomeEntityServiceImple implemenet SomeEntityService{ 
     @Transactional 
     save(SomeEntity se){ 
      //call to spring data's merge() method 
     } 

     get(Long id){ 
      //call to spring data's findOne() 
     } 

} 


//this class might be spring bean, might not be. If it is not I will get SomeEntityService bean from shared appContext 
class SomeCrazyClass{ 
    @Autowired 
    SomeEntityService service; 
    someMethod(){ 
     SomeEntity e = service.get(1L); 
     //do tons of logic here, change entity object, call some another methods and again, takes 3 seond 
     service.save(e); //Probably detached and someone updated this object, probably overriding it.  
    } 
} 
} 

Здесь я не могу двигаться, что tons of logic внутри слоя сервиса, весьма специфична и этот вид различных логик в 100х местах.

Итак, есть ли способ прийти и по крайней мере применить пессимистический замок к этой ситуации?

ответ

2

Для пессимистической блокировки, вы можете попробовать следующий код

  • Блокировка при выборке объект

    entityManager.find(Entity.class, pk, LockModeType.PESSIMISTIC_WRITE);

  • Применение Заблокируйте после

    entityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE);

  • Режим блокировки

    Установка в запросе

    query.setLockMode(LockModeType.PESSIMISTIC_WRITE);

Else, вы можете попробовать добавить синхронизированный метод в SomeEntityServiceImpl.

public synchronized void saveEntity(e){ 
{ 
Object o = get(id); //-- Fetch most recent entity 
applyChanges(o, e); //-- Applying custom changes 
save(o); //-- Persisting entity 
} 

Следовательно, вам не нужно перемещать всю вашу логику внутри службы, но делегировать только операции с базой данных.Кроме того, это будет общее место для изменений кода, не затрагивая логику приложения.

-1

Переместить аннотацию @Transactional на ваш верхний уровень на «someMethod» из «SomeCrazyClass». Изменения, внесенные в этот метод, должны быть частью одного транзакционного потока. Насколько я понимаю, этот поток должен быть атомарным, то есть должно быть все быть совершенным или без него (полный откат).

Внесение аннотации @Transactional выше одного метода с сохраненным сохранением не содержит точки этой аннотации. Вы все равно можете оставить его там (с использованием значения default.required default), но вы также должны добавить его на один уровень вверх.

Вы должны следовать этому предложению в своем приложении. Это означает, что вы должны обернуть свои бизнес-логические методы аннотацией Transactional.

+0

Класс 'SomeCrazyClass' здесь может быть любым, а не только фасолью. уже имеют уровень сервиса для аннотации @Transactional. – Elbek

+0

@elbek Если у вас есть автообновленная аннотация в SomeCrazyClass, она должна быть весенним бобом, не так ли? Так что, может быть, вы должны быть более точными с кодом, который вы публикуете. – forhas

+1

Пожалуйста, прочитайте комментарий к классу, я написал его: «Этот класс может быть весенним бобом, возможно, не так. Если это не так, я получаю компонент SomeEntityService из общего appContext» – Elbek