Antes de descrever o problema, deixe-me explicar algumas premissas. Suponha que a transação do banco de dados esteja configurada no arquivo de configuração do Spring da seguinte maneira:
<bean id="transactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
Agora existe UserDao e SecurityService:
@Repository public class UserDao { public User getUser() { // consulta o usuário da tabela do usuário return queryObject("select * from user order by id desc limit 1");
@Service @Transactional public class SecurityService { @Autowired private UserDao userDao; public void checkUserInfo() { while(true) { Usuário usuário = userDao.getUser(); ()) { System.out.println("Tom está aqui"); break;
Durante o processo de chamada do método SecurityService#checkUserInfo(), os dados obtidos por meio do método userDao#getUser() permanecem inalterados. Mesmo que um novo dado chamado Tom seja inserido neste momento, o loop não terminará. Além disso, remover a anotação @Transactional em SecurityService não ajudará.
Primeiro de tudo, pensei que poderia ser um problema com o pool de conexões do banco de dados. O mesmo acontece quando ele é substituído pelo próprio Spring. Então chamei o objeto Connection diretamente do JdbcTemplate e usei o método JDBC original para operar o banco de dados. Neste momento, os dados estavam mudando em tempo real, então pensei que deveria ser que a transação do Spring estivesse vinculada ao thread de operação atual. Após verificar o código fonte, descobri no método DataSourceUtils#doGetConnection que o Spring criou uma Connection em cada DataSource de cada thread e vinculou-a à transação. Como o arquivo de configuração orientado por tx:annotation executa vinculação de transação em todas as camadas de serviço (classes anotadas com @Service), a mesma conexão é vinculada no mesmo encadeamento, independentemente de @Transactional ser usado, mas não é executado apenas em operações de negócios. .
Depois de muitos experimentos e busca de informações, finalmente encontrei a solução perfeita: basta adicionar a anotação @Transactional(propagation = Propagation.NOT_SUPPORTED) ao método checkUserInfo acima. Claro, você também pode obter a Conexão e realizar a operação manualmente, ou pode usar o pacote DateUtils para realizar a operação.