Spring - предотвращение выполнения параллельных транзакций в нескольких таблицах - PullRequest
0 голосов
/ 02 мая 2018

У меня есть три таблицы T1, T2, T3 и четыре транзакции (A, B, C, D), которые выполняют следующие действия (это не очень важно для моего вопроса - в будущем может быть больше таблиц):

A - T1, T2 - чтение, T1, T2, T3 - запись
B - T1, T2, T3 чтение / запись
C, D - T1 - чтение, T3 чтение / запись.

У меня нет требований к производительности, поэтому я решил предотвратить одновременные транзакции:

  1. Я создал таблицу transactionlock с одной строкой.

  2. Я создал интерфейс JPA:

    @Repository
    public interface TransactionLockRepository extends JpaRepository<TransactionLock, Long> {
    
      @Lock(LockModeType.PESSIMISTIC_WRITE)
      @Query("select t from TransactionLock t")
      TransactionLock lock();
    
    }
    
  3. Я звоню lock() в начале каждой транзакции

    @Autowired
    private TransactionLockRepository lock;
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void transactionOne() {
      lock.lock();
      //my business code ...  
    }
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void transactionTwo() {
      lock.lock();
      //my business code ...  
    }
    

Программа, кажется, работает правильно, но я не уверен, что моя реализация абсолютно верна и не содержит ошибок.

ОБНОВЛЕНО

Если я пытаюсь синхронизировать транзакции без дополнительной таблицы, у меня возникает следующая проблема:

@Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE) 
public void businessLogic() {
  List<TableOne> data1 = tableOneRepository.findAll();
  sleep(300);
  List<TableTwo> data2 = tableTwoRepository.findAll();
  ... Some insert/delete/update queries for tableOne, tableTwo
}


@Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE) 
public void cleanEvent() {
  tableOneRepository.deleteAll();
  tableOneRepository.flush();
  tableTwoRepository.deleteAll();
  tableTwoRepository.flush();
}


public void execute() {
  transactions.businessLogic();
}

// In other thread
public void execute2() {
  sleep(100);
  transactions.cleanEvent();
}

Я хочу, чтобы первая транзакция была выполнена первой, но в этом случае у меня есть:

0) Транзакция 1 - начало

1) Транзакция 1 - чтение таблицы один

2) Транзакция 1 - сон 300

3) Транзакция 2 - начало

4) Транзакция 2 - удаление второй таблицы (не хочу!)

5) Транзакция 2 - удаление первой таблицы

6) Транзакция 1 - тупик (не могу прочитать таблицу два)

Можно ли решить эту проблему без дополнительной таблицы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...