5

我为它实现了一个服务entity object,它使用了 pure jpa,我使用了spring,所以spring xml config配置hibernate为一个jpaimpl。我正在使用spring数据进行crud操作。但是在我们的系统中,我们的entity对象被多次拉取/更新concurrency,并且数据存在高竞争()。从我们在许多地方的代码中,很多classes只是inject服务 bean 和调用getEntity方法来获取一个实体,之后他们更改实体(据我的理解,这是分离的,但在同一个线程中,所以 em 对象应该与我的知识相同)所以实体需要一段时间才能回到服务进行更新,他们调用save()服务的方法来保存实体。Save()方法只不过是调用merge()粗加工操作。它是带有@Transactional注释的事务性的。这里出现了一个问题,当有人拉动一个实体对象并且在更改它时其他人可能会拉动并更改它并将其保存回来,所以我的实体读取是脏的,如果保存它,我将覆盖已经更新的实体。问题是我们正在改变服务之外的实体并调用保存。这里 spring 数据存储库类是 DAO 层。

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在服务层中移动它,它非常具体,这种不同的逻辑存在于数百个地方。

那么有什么办法可以解决并至少对这种情况应用悲观锁定?

4

2 回答 2

3

对于悲观锁定,您可以尝试以下代码

  • 获取实体时锁定

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

  • 之后应用锁

    entityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE);

  • 在查询中设置锁定模式

    query.setLockMode(LockModeType.PESSIMISTIC_WRITE);

否则,您可以尝试在SomeEntityServiceImpl.

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

因此,您不必将所有逻辑移动到服务内部,而只需委托数据库操作。此外,它将是代码更改的常见场所,而不会影响应用程序逻辑。

于 2013-02-13T08:16:33.980 回答
-1

将@Transactional 注释移动到你的上层到“SomeCrazyClass”的“someMethod”。使用此方法所做的更改必须是一个事务流的一部分。据我所知,这个流程应该是原子的,这意味着它应该全部提交或不提交(完全回滚)。

将 @Transactional 注释单独放在退化的保存方法之上是缺少此注释的重点。您仍然可以将它留在那里(使用propagation.required 默认值),但您肯定还需要将它添加到上一级。

您应该在您的应用程序中遵循此建议。这意味着您应该使用 Transactional 注释来包装您的业务逻辑方法。

于 2013-02-15T19:35:31.727 回答