今天刚学到了双向异步的概念,听起来非常的高大上!!!
起因是这样的:我们在做的一个项目出现了并发量,把数据库给访问崩了...所以我们就用到了redis数据库和springMvc的定时器。
通过spring的定时器一秒访问一次数据库,再把数据存进redis里。再由前台的异步ajax访问controller层查询redis里有没有值,如果
redis里有值,通过状态查询返回不同的值。如果redis里没有值,返还一个空值,前台接收到一个空值,就不断的去controller里轮询。
这样的话本来10个、100个人都要去访问数据库,变成了去访问redis,优化效果很好!下面记录一下代码:
首先想用异步的话必须先配置,有几点:
1.在web.xml中加入
<async-supported>true</async-supported>
这串代码(ps:是web.xml 3.0的新特性)
2.在springMvc的配置中加入
xmlns:task="http://www.springframework.org/schema/task" 和
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
注意放的位置!!
这个是springMvc定时器的配置
3.在springMvc的配置中开启定时器
<!-- 开启Spring定时器 -->
<task:annotation-driven mode="proxy" scheduler="task"></task:annotation-driven>
<task:scheduler id="task" pool-size="10"></task:scheduler>
配置到这就完成了,接下来是代码部分。
--------------------------------------------------------------------------------------------------------------------------------------------------------
1.定时器工具类()
@Component
public class TaskAsync {
@Autowired
IUserDao daoSupport;
DateFormat df = new SimpleDateFormat("HH:mm:ss");//时间工具类
/*** @throws Exception
* * @auth: wang
* * @return:void
* * @description:同步订单 1 秒一次 (定时器)
* * 业务只提示 是否有新订单,不用记录订单具体详情 */
@Async
@Scheduled(cron = "*/5 * * * * ?")//定时每5秒执行一次
public void asyncOrder() throws Exception{
try {
/*
这里写的就是你怎么查询数据库 然后把数据放进redis即可
*/
//查询所有订单为0 也就是刚下单的状态的订单
List<Map> list = (List<Map>) daoSupport.selectForList("OrdersMapper.asyselect",null); //读取 数据库中的 status 为 0 的订单
JedisUtil.putKey("getOrders", list.size()==0? "": JSON.toJSONString(list),10);//有订单就存入进去 ,这个存的是所有刚下单的订单信息
JedisUtil.putKey("orders", list.size()==0? "" : list.size()+"",10);//没有订单就 是“”,有订单就不是0 这个存的是所有刚下单的订单个数
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
2.在controller里写一个方法 ,里面有个子线程 这样就不会耽误主线程
//双向异步
@RequestMapping(value = "/myorder",method = RequestMethod.GET)
@ResponseBody
@SysLog(module = "轮询redis" ,method="双向异步轮询")
public Callable<String> callable(HttpSession session) { //这个返回值的意思就是我返回线程的返回值
// Callable<String> 设置了线程的返回值是String
return new Callable<String>() {//开启线程
List<Map> lists = (List<Map>) session.getAttribute("list");//获取session
String str= lists.get(0).get("estates")+"";//取出session中我想要的特定值
String unfinished = "";//有未完成订单
String newOrder = "";//有新订单
@Override
public String call() throws Exception {
for(int i=0;i<30;i++) {//轮询30次
if (str.equals("1")){//如果str的值是1 就返回 unfinished
return "unfinished";
}else if(str.equals("0")){ //如果str的值是0
newOrder = JedisUtil.getKey("orders");//就获取redis里我们存的orders(里面存的是我们查询到的有几个值)
if ((!newOrder.equals("")) && newOrder != null){//如果orders的值不是空的 那返回 newOrder
return "newOrder";
}
}
Thread.sleep(1000);//线程睡1秒
}
return ""; //如果什么都查不到 就返回空
}
};
}
3.前台的ajax异步来访问controller层
<script type="text/javascript">
function async(){
layui.use('layer', function(){
var layer = layui.layer;
$.ajax({
async:true,//异步
url:"/gongchengshi/myorder",
type : 'get',
dataType:'text',
success : function(data) {
//console.log(data)
if(data=='unfinished'){
console.log("你有未完成订单")
alert('你有未完成订单!');
setTimeout(function(){
self.async();//执行完这次后 再调用自己一次去访问controller层
},10000);//等待10S继续执行
}else if(data=='newOrder'){
console.log("有新的可以接取订单")
alert('有新的可以接取订单!');
setTimeout(function(){
self.async();//执行完这次后 再调用自己一次去访问controller层
},10000);//等待10S继续执行
}else{
self.async();//如果返回的是空那么就一直执行自己 去访问controller层
}
}
});
});
}
async();
</script>
-------------------------------------------------------------------------------------------------------------------------------------------------------
总结:这是第一次遇到异步的问题,也明白了数据库优化的重要性。