使用Spring4.3解決緩存過期後多線程併發訪問數據庫的問題

緩存過期之後,如果多個線程同時請求對某個數據的訪問,會同時去到數據庫,導致數據庫瞬間負荷增高。Spring4.3爲@Cacheable註解提供了一個新的參數“sync”(boolean類型,缺省爲false),當設置它爲true時,只有一個線程的請求會去到數據庫,其他線程都會等待直到緩存可用。這個設置可以減少對數據庫的瞬間併發訪問。


不過不一定所有的緩存系統都支持這個配置。經過驗證,Guava Cache是支持的。驗證過程如下:


1、Guava Cache配置,參考:http://blog.csdn.net/clementad/article/details/51250472


2、創建從數據庫獲取數據的類和方法,該方法使用@Cacheable註解:

@Service
public class UserServiceCacheablesImpl implements UserServiceCacheables{
	private final static Logger logger = LoggerFactory.getLogger(UserServiceCacheablesImpl.class);

	@Autowired
	UserDAO userDAO;
	
	@Override
	@Cacheable(value="getPhoneNoByUserId")
	public String getPhoneNoByUserId(int userId) {
		logger.debug("getting data from database, userId={}", userId);
		return userDAO.getPhoneNoByUserId(userId);
	}
}


3、創建多線程併發的單元測試代碼:

@RunWith(SpringRunner.class)
@SpringBootTest
public class AdminApplicationTests {
	protected final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	UserServiceCacheables userServiceCacheables;
	
	/**
	 * 多線程併發測試
	 */
	@Test
	public void multiThreads() throws Exception{
		int number = 3; //線程數
		ExecutorService executorService = Executors.newFixedThreadPool(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 {
			return userServiceCacheables.getPhoneNoByUserId(userId);
		}
	}
}

4、測試結果:
當設置3個併發線程的時候,會出現3個log:“getting data from database, userId=26358”,說明訪問了3次數據庫。
當修改註解如下之後,只出現一次“getting data from database, userId=26358”,說明只訪問了1次數據庫,另外兩次命中了緩存:
@Cacheable(value="getPhoneNoByUserId", sync=true)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章