Spring中DAO被循环调用的时候数据不会实时更新的解决方法

在描述问题之前先说明几个前提,假设在Spring的配置文件中使用下面的方式配置了数据库的事务:


现在有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;
}
}
}
}

在调用SecurityService#checkUserInfo()方法的过程中,通过userDao#getUser()方法获取到的数据是不变的,即使这个时候新插入了一条name为Tom的数据循环也不会结束。另外将SecurityService上面的@Transactional注解去掉也无济于事。

首先想到会不会是数据库连接池的问题,换成了Spring自带的也是如此;然后从JdbcTemplate里面直接调用了Connection对象,使用原始的JDBC方式操作数据库,这个时候数据是实时变化的,于是想到应该是Spring的事务和当前操作线程进行绑定了。查看源代码进入之后果然在DataSourceUtils#doGetConnection方法里面发现了Spring在每个线程的每个DataSource上创建了一个Connection并且与事务进行了绑定。因为tx:annotation-driven配置文件对所有的Service层(加了@Service注解的类)进行了事务绑定,所以无论是否使用@Transactional都在同一个线程中绑定了同一个Connection,只是不进行事务操作而已。

经过多次实验和查找资料,最后终于找到了完美的解决方法:只要在上述的checkUserInfo方法中加上 @Transactional(propagation = Propagation.NOT_SUPPORTED) 注解就可以了。当然也可以获取到Connection然后手工进行操作,也可以使用DateUtils包进行操作。

参考资料:
Spring中的DataSource 事务 理解
Spring 之注解事务 @Transactional

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注