定时任务知多少(二)——持久化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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
在 C# ,可以使用 Quartz.NET 来实现定时任务,同时支持数据库持久化Quartz.NET 是一个功能强大且灵活的开源作业调度库,可以用于创建定时任务和计划任务,支持数据库持久化和集群部署等高级功能。 要使用 Quartz.NET 实现数据库持久化,需要先创建一个用于存储调度程序数据的数据库表,可以使用 Quartz.NET 提供的 SQL 脚本来创建表。然后在应用程序配置 Quartz.NET,指定数据库类型和连接字符串等信息。示例如下: ```csharp using Quartz; using Quartz.Impl; using Quartz.Impl.AdoJobStore; using Quartz.Spi; using System; using System.Collections.Specialized; class Program { static void Main() { Console.WriteLine("Starting scheduler..."); // 创建一个调度程序实例 ISchedulerFactory schedulerFactory = new StdSchedulerFactory(GetSchedulerProperties()); IScheduler scheduler = schedulerFactory.GetScheduler().Result; // 启动调度程序 scheduler.Start(); Console.WriteLine("Scheduler started."); // 创建一个作业实例 IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("job1", "group1") .Build(); // 创建一个触发器实例,每秒钟触发一次 ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(1) .RepeatForever()) .Build(); // 将作业和触发器添加到调度程序 scheduler.ScheduleJob(job, trigger); // 等待用户按下 Enter 键退出 Console.ReadLine(); // 关闭调度程序 scheduler.Shutdown(); Console.WriteLine("Scheduler stopped."); } static NameValueCollection GetSchedulerProperties() { // 配置调度程序属性,指定数据库持久化和相关参数 NameValueCollection properties = new NameValueCollection(); properties["quartz.scheduler.instanceName"] = "MyScheduler"; properties["quartz.scheduler.instanceId"] = "AUTO"; properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"; properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"; properties["quartz.jobStore.dataSource"] = "default"; properties["quartz.dataSource.default.provider"] = "SqlServer-20"; properties["quartz.dataSource.default.connectionString"] = "Server=(local);Database=Quartz;Trusted_Connection=True;"; return properties; } } public class HelloJob : IJob { public void Execute(IJobExecutionContext context) { Console.WriteLine("Hello, Quartz.NET!"); } } ``` 这个示例会创建一个调度程序实例,然后创建一个作业实例和触发器实例,并将它们添加到调度程序。作业类 HelloJob 实现了 IJob 接口,用于定义作业执行的逻辑。在 GetSchedulerProperties 方法,配置了调度程序属性,指定了数据库类型和连接字符串等信息。在这个示例,使用的是 SQL Server 数据库。 需要注意的是,在使用 Quartz.NET 进行数据库持久化时,需要保证数据库连接可靠和高效,同时需要考虑并发执行的问题。可以适当地调整作业和触发器的参数,以达到最优的性能和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值