Сколько транзакций мы получаем, когда два потока одновременно посещают метод с @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, а не в вашем коде.