定时任务知多少(二)——持久化quartz到Mongodb中

上文中,我们粗劣的介绍定时任务相关的知识。并且,我们初步了解了 Spring+quartz 的初步应用:将quartz放在内存中。

通过上文的分析,我们很容易看清:该种方式实现定时任务,较为简单,实现的功能也较为粗劣。由于我们直接把quartz放入内存中,等待执行;我们无法在它执行之前对它进行操作,比如任务暂停、删除等等。


今天,我们就来继续介绍可序列化的quartz的deno。

二、集成Spring,序列化Quartz到Mongodb中


首先,看一下Spring的如下配置:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	 http://www.springframework.org/schema/tx
	 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	 http://www.springframework.org/schema/jee
	 http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
	 http://www.springframework.org/schema/aop
	 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	 http://www.springframework.org/schema/context
	 http://www.springframework.org/schema/context/spring-context-3.0.xsd
	 http://activemq.apache.org/schema/core
	 http://activemq.apache.org/schema/core/activemq-core.xsd"
	default-lazy-init="true">

	<!--配置注解  -->
	<context:annotation-config/>
	<context:component-scan base-package="com.lzq.quartz" />
	
	<!--quartz调度器  -->
	<bean id="scheduler4Stock" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobFactory">
			<bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory" />
		</property>
<property name="configLocation" value="classpath:/spring/quartz_test.properties"></property>
	</bean>

</beans>


上面的添加方法中,定时任务管理器会将quartz序列化到Mongodb中。我们需要在下面job的配置quartz_test.properties中,配置Mongodb和Quartz的相关信息:

# Use the MongoDB store
org.quartz.jobStore.class=com.novemberain.quartz.mongodb.MongoDBJobStore
# MongoDB URI (optional if 'org.quartz.jobStore.addresses' is set)
org.quartz.jobStore.mongoUri=mongodb://localhost:27017
# comma separated list of mongodb hosts/replica set seeds (optional if 'org.quartz.jobStore.mongoUri' is set)
# org.quartz.jobStore.addresses=localhost
# database name
org.quartz.jobStore.dbName=test-hello-db 
# Will be used to create collections like mycol_jobs, mycol_triggers, mycol_calendars, mycol_locks
org.quartz.jobStore.collectionPrefix=world
# thread count setting is ignored by the MongoDB store but Quartz requries it
org.quartz.threadPool.threadCount=3
org.quartz.jobStore.misfireThreshold = 1800000


上面配置中,我们指定了org.quartz.jobStore.dbName=test-hello-db,这句的意思是我们定义存储quartz的库叫做test-hello-db;指定org.quartz.jobStore.collectionPrefix=world,设置表明的前缀为world(因为会生成多个表,所以要定义前缀,使其相邻且便于辨认)。


job,该类需要继承org.quartz.Job接口,我们可以把它理解成一个任务。这是定时任务到时间时,将要执行的该job类中的execute方法:

import org.apache.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;

/**
 *  库存相关的一个job
 * @author lzq
 *
 */
public class StockReturnJob implements Job {

	private Logger logger = Logger.getLogger(StockReturnJob.class);

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		
		JobDataMap jobDataMap = context.getTrigger().getJobDataMap();
		Scheduler scheduler = context.getScheduler();
		
		String userId = jobDataMap.getString("userId");
		String creditId = jobDataMap.getString("creditId");
		int num = jobDataMap.getInt("num");

		String orderId = context.getJobDetail().getKey().getName();
		String stockId = context.getJobDetail().getKey().getGroup();

		// 定时任务开始执行
		System.out.println("定时任务开始执行");
		System.out.println("jobDataMap中userId="+userId);
		System.out.println("jobDataMap中creditId="+creditId);
		System.out.println("jobDataMap中num="+num);
		
		// 移除触发器
//		TriggerKey triggerKey = new TriggerKey(orderId, stockId);
//		try {
//			scheduler.unscheduleJob(triggerKey);
//		} catch (SchedulerException e) {
//			e.printStackTrace();
//		}

	}

}


下面这个类中,我们定义了定时任务的管理器,在这里,我们添加定时任务、删除定时任务……,同时,我们也可以多定时进行其他操作,如暂定、对触发器进行移出等等操作,本例只提供最基本的介绍,帮助大家快速上手quartz,其他内容,请大家在网络上寻找其他资料。

import java.util.Calendar;

import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.lzq.tool.quartz.schedule.StockReturnJob;

@Component
public class OrderQuartz{
	
	@Autowired
	private Scheduler scheduler4Stock;
	
	/**
	 * 添加一个定时任务
	 * @param orderId
	 * @param stockId
	 */
	public void addQuartz(String orderId,String stockId){
		
		//创建一个job
		JobDetailImpl jobDetail = new JobDetailImpl();
		jobDetail.setJobClass(StockReturnJob.class);
		jobDetail.setKey(new JobKey(orderId, stockId));
		
		//job的数据
		JobDataMap jobDataMap = new JobDataMap();
		jobDataMap.put("stockId", stockId);
		jobDataMap.put("orderId", orderId);
		jobDataMap.put("userId", "user_id_test");
		jobDataMap.put("num",1024);
		
		SimpleTriggerImpl strigger = new SimpleTriggerImpl();
		strigger.setKey(new TriggerKey(orderId, stockId));
		
		 //设置执行时间
		Calendar ca = Calendar.getInstance();
		ca.add(Calendar.SECOND,45*60);
		strigger.setStartTime(ca.getTime());  
		strigger.setJobDataMap(jobDataMap);
		try {
			//开始一个定时任务
			scheduler4Stock.scheduleJob(jobDetail, strigger);
		} catch (SchedulerException e1) {
			e1.printStackTrace();
		}
    	
    }
	
	/**
	 * 删除一个定时任务
	 * @param orderId
	 * @param stockId
	 * @return true,删除成功;false,删除失败
	 */
	public boolean deleteQuartz(String orderId,String stockId){
		JobKey jk =new JobKey(orderId,stockId);
		boolean deleteFlag = false;
		try {
			deleteFlag = scheduler4Stock.deleteJob(jk);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
		return deleteFlag;
	}
}


通过如下程序,运行测试。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import com.lzq.tool.quartz.OrderQuartz;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
		"classpath:spring/spring.xml"
})
@TransactionConfiguration(transactionManager="transactionManager",defaultRollback=false)
@Transactional
public class QuartzTest{
	@Autowired
	private OrderQuartz orderQuartz;
	
	@Test
	public void testAddOrder() throws Exception {
		String orderId ="test-order-lzq1";
		String stockId ="test-stock-lzq1";
		orderQuartz.addQuartz(orderId, stockId);
	}
	
	
}


运行结果,会在Mongodb中生成test-hello-db库,且生成的表如下:

生成如上图的四个表,我们会发现,world_locks表总是空的,但是为什么会生成过它呢?从名称上即可做出做好的猜测。加锁,没错。比如多个线程同时添加同一个定时任务(比如,多个用户同时对同一款产品的同一个库存进行操作),如何才能正确条件定时任务呢?其实想到锁,这个问题就很好结局了,大家完全可以把当做乐观锁来处理。

本篇文章介绍的可持久化的定时任务,使用起来比较灵活,用在订单过期、库存失效等业务上非常合适。


实例下载地址:http://download.csdn.net/detail/liu765023051/9240055

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值