在库存服务中实现缓存与数据库双写一致性保障方案(三)
public interface Request {
void process();
Integer getProductId();
}
接口增加一个获取id的方法。
请求内存队列,做一个统一的入口和出口,需要单例
package com.roncoo.eshop.req; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; /** * 请求内存队列 * @author Administrator * */ public class RequestQueue { /** * 内存队列 */ private List<ArrayBlockingQueue<Request>> queues = new ArrayList<ArrayBlockingQueue<Request>>(); /** * 单例有很多种方式去实现:我采取绝对线程安全的一种方式 * * 静态内部类的方式,去初始化单例 * * @author Administrator * */ private static class Singleton { private static RequestQueue instance; static { instance = new RequestQueue(); } public static RequestQueue getInstance() { return instance; } } /** * jvm的机制去保证多线程并发安全 * * 内部类的初始化,一定只会发生一次,不管多少个线程并发去初始化 * * @return */ public static RequestQueue getInstance() { return Singleton.getInstance(); } /** * 添加一个内存队列 * @param queue */ public void addQueue(ArrayBlockingQueue<Request> queue) { this.queues.add(queue); } /** * 获取内存队列的数量 * @return */ public int queueSize() { return queues.size(); } /** * 获取内存队列 * @param index * @return */ public ArrayBlockingQueue<Request> getQueue(int index) { return queues.get(index); } }
项目初始化就把队列数据初始化好。
package com.roncoo.eshop.service; import com.roncoo.eshop.req.Request; import com.roncoo.eshop.req.RequestQueue; import java.util.concurrent.ArrayBlockingQueue; public class RequestAsyncProcessServiceImpl implements RequestAsyncProcessService { /*** *做请求的路由,根据每个请求的商品id,路由到对应的内存队列中去 * @param request */ @Override public void process(Request request) { try { /** * 根据id去hash集合中的位置,获取到位置的queue,把数据加到queue中。 */ ArrayBlockingQueue<Request> routingQueue = getRoutingQueue(request.getProductId()); routingQueue.put(request); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 获取路由到的内存队列 */ public ArrayBlockingQueue<Request> getRoutingQueue(Integer productId) { RequestQueue requestQueue = RequestQueue.getInstance(); String key = String.valueOf(productId); int h; int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); // //得到的hash值 int index = (requestQueue.queueSize() - 1) & hash; return requestQueue.getQueue(index); } }
增加一个service的方法,从缓存获取库存的方法。
/** * 获取缓存中的库存数量 * @param productId * @return */ @Override public ProductInventory getProductInventoryCache(Integer productId) { Long inventoryCnt =0L; String key= "product:inventory:"+productId; String result = redisDAO.get(key); if (result != null&&!"".equals(result)){ inventoryCnt = Long.valueOf(result); return new ProductInventory(productId,inventoryCnt); } return null; }
更新商品库存的时候,把请求加到异步请求队列中
查询商品库存的时候,加到异步请求的队列的路由中, 如果规定时间内没查到缓存数据,就查询数据库
package com.roncoo.eshop.controller; import com.roncoo.eshop.entity.ProductInventory; import com.roncoo.eshop.entity.Response; import com.roncoo.eshop.req.DataUpdateRequest; import com.roncoo.eshop.req.ProductInventoryCacheRefreshRequest; import com.roncoo.eshop.req.Request; import com.roncoo.eshop.service.ProductInventoryService; import com.roncoo.eshop.service.RequestAsyncProcessService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; /** * 商品库存Controller * @author Administrator * */ @Controller public class ProductInventoryController { @Resource private RequestAsyncProcessService requestAsyncProcessService; @Resource private ProductInventoryService productInventoryService; /** * 更新商品库存 */ @RequestMapping("/updateProductInventory") @ResponseBody public Response updateProductInventory(ProductInventory productInventory) { Response response = null; try { //商品id,商品数量。商品库存Service接口 Request request = new DataUpdateRequest( productInventory, productInventoryService); requestAsyncProcessService.process(request); /** * 返回状态 */ response = new Response(Response.SUCCESS); } catch (Exception e) { e.printStackTrace(); response = new Response(Response.FAILURE); } return response; } /** * 获取商品库存 */ @RequestMapping("/getProductInventory") @ResponseBody public ProductInventory getProductInventory(Integer productId) { ProductInventory inventory = null; try { ProductInventoryCacheRefreshRequest request = new ProductInventoryCacheRefreshRequest(productId, productInventoryService); //把数据加到内存队列中 requestAsyncProcessService.process(request); //开始时间,结束时间 long startTime = System.currentTimeMillis(); Long endTime =0L; Long waitTime =0L; while (true){ if(waitTime >200){ break; } //尝试redis读取缓存数据 inventory = productInventoryService.getProductInventoryCache(productId); if(inventory !=null){ return inventory; }else{ Thread.sleep(20); endTime = System.currentTimeMillis(); waitTime = endTime - startTime; } } // 直接尝试从数据库中读取数据 inventory = productInventoryService.findProductInventory(productId); if(inventory !=null){ return inventory; } } catch (InterruptedException e) { e.printStackTrace(); } return new ProductInventory(productId, -1L); } }
---------------------------------------------------------------------------
国之殇,未敢忘!
南京大屠杀!
731部队!
以及核污染水排海等一系列全无人性的操作,购买他们的食品和为它们提供帮助只会更加变本加厉的害你,呼吁大家不要购买日本相关产品
昭昭前事,惕惕后人
吾辈当自强,方使国不受他人之侮!
---------------------------------------------------------------------------
作者:三号小玩家
出处:https://www.cnblogs.com/q1359720840/
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。 版权信息