现在考评的学生提交答题记录的基本流程如下:
考虑到答题记录提交频繁,并且同一时间内有多个学生提交答题记录,所以我们考虑到向数据库提交答题记录时用mq作为缓冲,这样既可以提高提交速度也可以减轻数据库的压力;把答题记录同时向redis中提交一份是为了方便学生二次登陆时对答题记录的查询。
这次我们首先来看mq具体是如何使用的?
首先我们来看mq最重要的地方,配置文件spring-rabbitmq.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<!-- 定义RabbitMQ的连接工厂_郑涛 -->
<rabbit:connection-factory id="connectionFactory"
host="192.168.22.232" port="5672" username="zhengtao" password="zhengtao"
virtual-host="examination-OnlineExam" />
<!-- 定义Rabbit模板,指定连接工厂以及定义exchange -->
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" exchange="fanoutExchange" />
<!-- <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
exchange="fanoutExchange" routing-key="foo.bar" /> -->
<!-- MQ的管理,包括队列、交换器等 -->
<rabbit:admin connection-factory="connectionFactory" />
<!-- 定义队列,自动声明 -->
<rabbit:queue name="myQueue" auto-declare="true"/>
<!-- 定义交换器,自动声明 -->
<rabbit:fanout-exchange name="fanoutExchange" auto-declare="true">
<rabbit:bindings>
<rabbit:binding queue="myQueue"/>
</rabbit:bindings>
</rabbit:fanout-exchange>
<!-- <rabbit:topic-exchange name="myExchange">
<rabbit:bindings>
<rabbit:binding queue="myQueue" pattern="foo.*" />
</rabbit:bindings>
</rabbit:topic-exchange> -->
<!-- 队列监听:acknowledge确认机制 默认是开启的呃;auto属性代表一发消息既代表收到,不可取自动接收acknowledge="auto"-->
<rabbit:listener-container connection-factory="connectionFactory" >
<rabbit:listener ref="foo" method="listen" queue-names="myQueue" />
</rabbit:listener-container>
<!--消费者 -->
<bean id="foo" class="com.dmsdbj.itoo.examinationEvaluation.service.impl.OnlineExamServiceImpl" />
</beans>
如果,mq的服务器已经搭建好,其实我们在这个配置文件上改起来是比较简单的
1、修改连接工厂中的配置(以下是三个需要修改的属性)
username="zhengtao" password="zhengtao"
virtual-host="examination-OnlineExam"
2、定义队列中,名称改为我们自己的队列
name="myQueue"
3、定义交换器中,绑定的队列名称改为自己的队列
<rabbit:binding queue="myQueue"/>
4、队列监听和消费者全都要改为自己对应的。
生产者:
1、注入rabbitmq
//注入rabbitmq,用于提交考试记录--郑涛
@Autowired
private RabbitTemplate rabbitTemplate;
2、发送消息
//region mq生产者,将记录提交到rebbitmq--郑涛--2017年9月12日
String studentId = paperRecordEntity.getStudentId();
String paperId = paperRecordEntity.getPaperId();
String typeId = paperRecordEntity.getQuestionTypeId();
String mainId = paperRecordEntity.getQuestionMainId();
String studentAnswer = paperRecordEntity.getStudentAnswer();
String studentScore = paperRecordEntity.getScore().toString();
//提交到消息队列的消息
String msg = studentId+";"+paperId+";"+typeId+";"+mainId+";"+studentAnswer+";"+studentScore;
//作为生产者将消息加入mq
rabbitTemplate.convertAndSend(msg);
//endregion
消费者:
这里的消费者,就是我们配置文件中配置的监听类
public void listen(String foo){
if (StringUtil.isNotEmpty(foo)){
//1.打印监听的消息内容(后期可删除)
// System.out.println("消费者:++++++++++++++++++++ " + foo);
//将消息按分号分隔放入数组
String[] Strlist = foo.split(";");
//定义变量并赋值
String studentId = Strlist[0].toString();
String paperId = Strlist[1].toString();
String typeId = Strlist[2].toString();
String mainId = Strlist[3].toString();
String studentAnswer = Strlist[4].toString();
String studentScore = Strlist[5].toString();
//变量给实体赋值,用于更新到数据库
PaperRecordEntity paperRecordEntity = new PaperRecordEntity();
paperRecordEntity.setStudentId(studentId);
paperRecordEntity.setPaperId(paperId);
paperRecordEntity.setQuestionTypeId(typeId);
paperRecordEntity.setQuestionMainId(mainId);
paperRecordEntity.setStudentAnswer(studentAnswer);
paperRecordEntity.setScore(Double.parseDouble(studentScore));
PaperRecordExample paperRecordExample = new PaperRecordExample();
PaperRecordCriteria paperRecordCriteria = paperRecordExample.createCriteria();
//更新条件
paperRecordCriteria.andPaperIdEqualTo(paperRecordEntity.getPaperId());//试卷ID
paperRecordCriteria.andQuestionTypeIdEqualTo(paperRecordEntity.getQuestionTypeId());//题型ID //Todo 待考虑要不要将题型作为条件查询答题记录
paperRecordCriteria.andQuestionMainIdEqualTo(paperRecordEntity.getQuestionMainId());//题干ID
paperRecordCriteria.andStudentIdEqualTo(paperRecordEntity.getStudentId());//学生ID
Byte isDelete = 0;
paperRecordCriteria.andIsDeleteEqualTo(isDelete);
//将数据更新入库
int result = paperRecordDao.updateByExample(paperRecordEntity,paperRecordExample);
}
}
现在我们的监听发方法是由spring的容器管理的,不用我们自己开线程写死循环一直监听执行,当队列中有消息时,程序会自动运行到监听方法。我测试的时候当程序运行完
rabbitTemplate.convertAndSend(msg);
的时候会自动调到监听方法,断点可以命中。
以上即为mq的具体使用过程。