Прежде чем описывать проблему, позвольте мне объяснить несколько предпосылок. Предположим, что транзакция базы данных настроена в файле конфигурации Spring следующим образом:
<bean id="transactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
Теперь есть UserDao и SecurityService:
@Repository public class UserDao { public User getUser() { // запрос пользователя из пользовательской таблицы return queryObject("select * from user order by id desc limit 1");
@Service @Transactional public class SecurityService { @Autowired Private UserDao userDao; ()) { System.out.println("Том здесь" } } } };
В процессе вызова метода SecurityService#checkUserInfo() данные, полученные с помощью метода userDao#getUser(), остаются неизменными. Даже если в этот момент будут вставлены новые данные с именем Tom, цикл не завершится. Кроме того, удаление аннотации @Transactional в SecurityService не поможет.
Прежде всего, я подумал, что это может быть проблема с пулом подключений к базе данных. То же самое происходит, когда он заменяется собственным пулом Spring. Затем я вызвал объект Connection непосредственно из JdbcTemplate и использовал исходный метод JDBC для управления базой данных. В это время данные менялись в реальном времени, поэтому я подумал, что транзакция Spring должна быть привязана к текущему потоку операции. Проверив исходный код, я обнаружил в методе DataSourceUtils#doGetConnection, что Spring создал соединение для каждого источника данных каждого потока и привязал его к транзакции. Поскольку файл конфигурации, управляемый tx:annotation, выполняет привязку транзакций ко всем уровням службы (классам, помеченным @Service), одно и то же соединение привязывается к одному и тому же потоку независимо от того, используется ли @Transactional, но не выполняется только бизнес-операции. .
После многих экспериментов и поиска информации я наконец нашел идеальное решение: просто добавьте аннотацию @Transactional(propagation = Propagation.NOT_SUPPORTED) к приведенному выше методу checkUserInfo. Конечно, вы также можете получить Connection и выполнить операцию вручную или использовать пакет DateUtils для выполнения операции.