在描述問題之前先說明幾個前提,假設(shè)在Spring的配置文件中使用下面的方式配置了數(shù)據(jù)庫的事務(wù):
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
現(xiàn)在有UserDao和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; } } } }
在調(diào)用SecurityService#checkUserInfo()方法的過程中,通過userDao#getUser()方法獲取到的數(shù)據(jù)是不變的,即使這個時候新插入了一條name為Tom的數(shù)據(jù)循環(huán)也不會結(jié)束。另外將SecurityService上面的@Transactional注解去掉也無濟(jì)于事。
首先想到會不會是數(shù)據(jù)庫連接池的問題,換成了Spring自帶的也是如此;然后從JdbcTemplate里面直接調(diào)用了Connection對象,使用原始的JDBC方式操作數(shù)據(jù)庫,這個時候數(shù)據(jù)是實時變化的,于是想到應(yīng)該是Spring的事務(wù)和當(dāng)前操作線程進(jìn)行綁定了。查看源代碼進(jìn)入之后果然在DataSourceUtils#doGetConnection方法里面發(fā)現(xiàn)了Spring在每個線程的每個DataSource上創(chuàng)建了一個Connection并且與事務(wù)進(jìn)行了綁定。因為tx:annotation-driven配置文件對所有的Service層(加了@Service注解的類)進(jìn)行了事務(wù)綁定,所以無論是否使用@Transactional都在同一個線程中綁定了同一個Connection,只是不進(jìn)行事務(wù)操作而已。
經(jīng)過多次實驗和查找資料,最后終于找到了完美的解決方法:只要在上述的checkUserInfo方法中加上 @Transactional(propagation = Propagation.NOT_SUPPORTED) 注解就可以了。當(dāng)然也可以獲取到Connection然后手工進(jìn)行操作,也可以使用DateUtils包進(jìn)行操作。
新聞熱點
疑難解答
圖片精選