使⽤Spring4.3解决缓存过期后多线程并发访问数据库
的问题
版权声明:本⽂为原创⽂章,转载请注明转⾃Clement-Xu的csdn博客。 blog.csdn/ClementAD/article/details/52452119
缓存过期之后,如果多个线程同时请求对某个数据的访问,会同时去到数据库,导致数据库瞬间负荷增⾼。Spring4.3为@Cacheable注解提供了⼀个新的参数“sync”(boolean类型,缺省为false),当设置它为true时,只有⼀个线程的请求会去到数据库,其他线程都会等待直到缓存可⽤。这个设置可以减少对数据库的瞬间并发访问。
不过不⼀定所有的缓存系统都⽀持这个配置。经过验证,Guava Cache是⽀持的。验证过程如下:
1、Guava Cache配置,参考:
2、创建从数据库获取数据的类和⽅法,该⽅法使⽤@Cacheable注解:cacheable
@Service
public class UserServiceCacheablesImpl implements UserServiceCacheables{
private final static Logger logger = Logger(UserServiceCacheablesImpl.class);
@Autowired
UserDAO userDAO;
@Override
@Cacheable(value="getPhoneNoByUserId")
public String getPhoneNoByUserId(int userId) {
logger.debug("getting data from database, userId={}", userId);
PhoneNoByUserId(userId);
}
}
3、创建多线程并发的单元测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class AdminApplicationTests {
protected final Logger logger = Class());
@Autowired
UserServiceCacheables userServiceCacheables;
/**
* 多线程并发测试
*/
@Test
public void multiThreads() throws Exception{
int number = 3; //线程数
ExecutorService executorService = wFixedThreadPool(number);
List<Future<String>> results = new ArrayList<Future<String>>();
int userId = 26358;
for (int i=0; i < number; i++) { //⾮阻塞地启动number个线程,由Future接收结果
Future<String> future = executorService.submit(new MyThread(userId));
//Thread.sleep(300);
results.add(future);
}
for(Future<String> f : results){ //从Future中获取结果,打印出来
String phoneNo = f.get();
logger.debug(phoneNo);
}
}
class MyThread implements Callable<String>{
int userId;
public MyThread(int userId) {
this.userId = userId;
}
@Override
public String call() throws Exception {
PhoneNoByUserId(userId);
}
}
}
4、测试结果:
当设置3个并发线程的时候,会出现3个log:“getting data from database, userId=26358”,说明访问了3次数据库。
当修改注解如下之后,只出现⼀次“getting data from database, userId=26358”,说明只访问了1次数据库,另外两次命中了缓存:@Cacheable(value="getPhoneNoByUserId", sync=true)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。