Вопрос по java – JPA Вложенные транзакции и блокировка

18

Рассмотрим сценарий, в котором два разных метода существуют без учета состояния.

public class Bean_A {
   Bean_B beanB; // Injected or whatever
   public void methodA() {
    Entity e1 = // get from db
    e1.setName("Blah");
    entityManager.persist(e1);
    int age = beanB.methodB();

   }
} 
public class Bean_B {
  //Note transaction
  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
   public void methodB() {

    // complex calc to calculate age  
  }

}

Транзакция, начатая BeanA.methodA, будет приостановлена, и новая транзакция будет запущена в BeanB.methodB. Что, если methodB нужен доступ к той же сущности, которая была изменена methodA. Это может привести к тупику. Можно ли это предотвратить, не полагаясь на уровни изоляции?

Как и где вы попали в тупик? Из кеша сессии или из базы данных заблокированных строк? Yves Martin

Ваш Ответ

4   ответа
1

Вотнедавняя статья об использованииREQUIRES_NEW демаркация транзакции.

Из моего опыта не должно быть тупиков со стандартным кодом: запросы с ограничениемwhere оговорка и несколько вставок. В некоторых конкретных случаях некоторые ядра СУБД могут выполнять эскалацию блокировки, если во время транзакции прочитано или вставлено много строк в одну таблицу ... и в этом случае может возникнуть мертвая блокировка.

Но в этом случае проблема не исходит отREQUIRES_NEW но из дизайна SQL. Если этот дизайн не может быть улучшен, у вас нет другого выбора, чтобы изменить уровень изоляции на более свободный уровень.

3

Pass the entity and merge...

Вы можете передать свой новый объектmethodB()и объединить его с новымEntityManager, Когда метод вернется, обновите вашу сущность, чтобы увидеть изменения:

public class Bean_A {
  Bean_B beanB; // Injected or whatever
  public void methodA() {
    Entity e1 = // get from db
    e1.setName("Blah");
    entityManager.persist(e1);
    int age = beanB.methodB(e1);
    entityManager.refresh(e1);
  }
} 

public class Bean_B {
  //Note transaction
  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  public void methodB(Entity e1) {
    e1 = entityManager.merge(e1);
    // complex calc to calculate age  
  }

}

Обратите внимание, что это передаст вашу сущность, когда новая транзакция закроется послеmethodB.

...or save it before calling methodB

Если вы используете описанный выше метод, сущность сохраняется отдельно от вашей основной транзакции, поэтому вы ничего не потеряете, если сохраните ее изBean_A перед звонкомmethodB():

public class Bean_A {
  Bean_B beanB; // Injected or whatever

  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  public void createEntity() {
    Entity e1 = // get from db
    e1.setName("Blah");
    entityManager.persist(e1);
  }

  public void methodA() {
    createEntity()   
    int age = beanB.methodB();
  }
} 

public class Bean_B {
  //Note transaction
  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  public void methodB() {

    // complex calc to calculate age  
  }

}
0

программно совершая транзакцию послеentityManager.persist(e1);  и раньшеint age = beanB.methodB();?

public class Bean_A {
   Bean_B beanB; // Injected or whatever
   public void methodA() {
    EntityManager em = createEntityManager();
    Entity e1 = // get from db
    e1.setName("Blah");
    entityManager.persist(e1);
    em.getTransaction().commit();
    int age = beanB.methodB();

   }
} 
public class Bean_B {
  //Note transaction
  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
   public void methodB() {

    // complex calc to calculate age  
  }

}

EDIT: CMT

Если у вас есть CMT, вы все еще можете совершать программно, вы просто получаете транзакцию отEJBContext, например.:http://geertschuring.wordpress.com/2008/10/07/how-to-use-bean-managed-transactions-with-ejb3-jpa-and-jta/

или вы можете добавить@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void methodC() который бы сделалe1.setName("Blah"); entityManager.persist(e1);то есть он будет сохраняться в транзакции e1. тогда вашmethodA() назвал бы

methodC();
beanB.methodB(); 
Error: User Rate Limit Exceeded anergy
Error: User Rate Limit Exceeded anergy
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededmethodC()Error: User Rate Limit Exceeded@TransactionAttributeError: User Rate Limit Exceededlocal method trapError: User Rate Limit Exceededlocal method trapError: User Rate Limit Exceededentjavastuff.blogspot.com/2011/02/…Error: User Rate Limit Exceeded
21

Хм, давайте перечислим все случаи.

REQUIRES_NEW действительно не вкладывает транзакции, но, как вы упомянули, приостанавливает текущую. Затем просто две транзакции обращаются к одной и той же информации. (Это аналогично двум обычным параллельным транзакциям, за исключением того, что они не параллельны, а находятся в одном потоке выполнения).

T1 T2          T1 T2
―              ―
|              |
               |
   ―           |  ―
   |           |  |
   |     =     |  |
   ―           |  ―
               |
|              |
―              ―

Тогда нам нужно рассмотретьoptimistic противpessimistic замок.

Также нам нужно учестьflushes управляется ОРМ. С ORM у нас нет четкого контроля, когда происходит запись, так какflush контролируется рамками. Обычно одно неявное сбрасывание происходит перед фиксацией, но если много записей изменено, каркас может также выполнять промежуточные сбрасывания.

1) Давайте рассмотрим оптимистическую блокировку, когда чтение не получает блокировки, а запись получает эксклюзивные блокировки.

Чтение T1 не получает блокировку.

1a) Если T1 действительно сбросил изменения преждевременно, он получил эксклюзивную блокировку. Когда T2 фиксирует, он пытается получить блокировку, но не может.The system is blocked. Это может быть определенный тупик. Завершение зависит от времени ожидания транзакций или блокировок.

1b) Если T1 не сбросил изменения преждевременно, блокировка не была получена. Когда T2 фиксирует, он получает и освобождает его и является успешным. Когда T1 пытается зафиксировать, он замечает конфликт и терпит неудачу.

2) Давайте рассмотрим пессимистическую блокировку, когда чтение получает общие блокировки и пишет эксклюзивные блокировки.

Чтение T1 получает общую блокировку.

2a) Если T1 покраснел недоношенно, он превращает блокировку в эксклюзивную блокировку. Ситуацияsimilar as 1a)

2b) Если T1 не сбрасывал преждевременно, T1 удерживает общую блокировку. Когда T2 фиксирует, он пытается получить эксклюзивную блокировку и блоки.The system is blocked again.

Вывод: все в порядке с оптимистической блокировкой, если не происходит преждевременных сбросов, которые вы не можете строго контролировать.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы