Сколько транзакций мы получаем, когда два потока одновременно посещают метод с @Transactional?

Допустим, у нас есть этот код:

@Transactional
public String getUser(long id) {

    User user = userDao.getUserById(id);
    if(user == null) {
        user = new User();
        user.setXXX(XXX);
        userDao.insert(user);
    }   
}

Предполагая, что источник данных mysql5:

Сколько транзакций мы получаем, если два потока посещают getUser() метод в то же время? Если ответ два, то какова связь между двумя транзакциями?

2 ответа

Решение

По состоянию на весну Документация:

Метод getTransaction(..) возвращает объект TransactionStatus в зависимости от параметра TransactionDefinition. Возвращенный TransactionStatus может представлять новую транзакцию или может представлять существующую транзакцию, если соответствующая транзакция существует в текущем стеке вызовов. В последнем случае подразумевается, что, как и в контексте транзакций Java EE, TransactionStatus связан с потоком выполнения.

Это означает, что для каждого потока Spring создаст новую транзакцию, если она еще не существует для этого потока.

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

Сколько транзакций мы получаем, если два потока посещают метод getUser() одновременно?

Ответ зависит от фабрики соединений и типа базы данных. Если вы используете пул соединений или иным образом создаете два соединения, то каждый поток получит отдельную транзакцию с базой данных. Детали здесь сильно зависят от вашего пула соединений и настроек базы данных.

Если ответ два, то какова связь между двумя транзакциями?

Это зависит от того, что база данных делает с этими транзакциями. Важно понимать, что транзакции связаны не с мьютексом, а с согласованностью базы данных. Цитировать из Википедии:

Транзакция символизирует единицу работы, выполняемую в системе управления базой данных (или аналогичной системе) в отношении базы данных, и обрабатывается согласованным и надежным способом, независимым от других транзакций. Транзакция обычно представляет любое изменение в базе данных.

То, как транзакции взаимодействуют, сильно зависит от того, какой тип транзакции создается и что делается внутри них. Если вы спрашиваете, возможно ли 2 потока для поиска User с тем же идентификатором в то же время, а затем попробуйте и создать тот же User дважды, тогда ответ окончательно да.

Одна проблема с этим заключается в том, что оба userDao.insert(...) вызовы могут быть успешными, но 2-ой из них для подтверждения своей транзакции (предупреждение о состоянии гонки) может вызвать какое-то уникальное исключение ограничения, но это может произойти на уровне AOP, а не в вашем коде.

Другие вопросы по тегам