Before describing the problem, let me explain a few premises. Assume that the database transaction is configured in the Spring configuration file in the following way:
<bean id="transactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
Now there is UserDao and SecurityService:
@Repository public class UserDao { public User getUser() { // query user from user table 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) { User user = userDao.getUser(); if(user != null && "Tom".equals(user.getName ()) { System.out.println("Tom is here"); break; } } } }
During the process of calling the SecurityService#checkUserInfo() method, the data obtained through the userDao#getUser() method remains unchanged. Even if a new data named Tom is inserted at this time, the loop will not end. In addition, removing the @Transactional annotation on SecurityService will not help.
First of all, I thought that it might be a problem with the database connection pool. The same is true when it is replaced by Spring's own one. Then I called the Connection object directly from JdbcTemplate and used the original JDBC method to operate the database. At this time, the data was changing in real time, so I thought It should be that Spring's transaction is bound to the current operation thread. After checking the source code, I found in the DataSourceUtils#doGetConnection method that Spring created a Connection on each DataSource of each thread and bound it to the transaction. Because the tx:annotation-driven configuration file performs transaction binding on all Service layers (classes annotated with @Service), the same Connection is bound in the same thread regardless of whether @Transactional is used, but it is not performed. Just business operations.
After many experiments and searching for information, I finally found the perfect solution: just add the @Transactional(propagation = Propagation.NOT_SUPPORTED) annotation to the above checkUserInfo method. Of course, you can also obtain the Connection and perform the operation manually, or you can use the DateUtils package to perform the operation.