达梦数据库备份-Quartz定时任务备份
定时任务备份为创建定时任务,定时的去备份数据库,使用quartz做定时任务(存在spring无法管理quartz类的问题),并将定时任务的信息保存到数据库实现定时任务的增删改查和数据还原,然后将备份代码集成到quartz中。
代码中只实现table级别的备份,全局备份只是导出语句不同
1. Quartz集成到springboot
pom文件添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
quartz的配置类
/** * * 任务调度管理器 */ @Configuration public class QuartzConfig { private MyJobFactory jobFactory; public QuartzConfig(MyJobFactory jobFactory) { this.jobFactory = jobFactory; } /** * 配置SchedulerFactoryBean * 将一个方法产生为Bean并交给Spring容器管理 */ @Bean public SchedulerFactoryBean schedulerFactoryBean() { // Spring提供SchedulerFactoryBean为Scheduler提供配置信息,并被Spring容器管理其生命周期 SchedulerFactoryBean factory = new SchedulerFactoryBean(); // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 factory.setOverwriteExistingJobs(true); // 设置自定义Job Factory,用于Spring管理Job bean factory.setJobFactory(jobFactory); return factory; } @Bean(name = "scheduler") public Scheduler scheduler() { return schedulerFactoryBean().getScheduler(); } }
自定义job类
@Component public class MyJobFactory extends AdaptableJobFactory { /** * AutowireCapableBeanFactory接口是BeanFactory的子类 * * 可以连接和填充那些生命周期不被Spring管理的已存在的bean实例 */ private AutowireCapableBeanFactory factory; public MyJobFactory(AutowireCapableBeanFactory factory) { this.factory = factory; } /** * 创建Job实例 */ @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { // 实例化对象 Object job = super.createJobInstance(bundle); // 进行注入(Spring管理该Bean) factory.autowireBean(job); // 返回对象 return job; } }
定时任务的工具类
@Service public class SchedulerUtil { @Autowired private Scheduler scheduler; private final static Logger LOGGER = LoggerFactory.getLogger(SchedulerUtil.class); /** * @Description: 任务执行类 */ private static SchedulerFactory schedulerFactory = new StdSchedulerFactory(); private static String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME"; private static String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME"; /** * 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名 * * @param jobName 任务名 * @param cls 任务 * @param time 时间设置,参考quartz说明文档 */ public void addJob(String jobName, Class cls, String time, Map<String, Object> map) { try { // Scheduler scheduler = schedulerFactory.getScheduler();//创建一个触发器表 JobDetail jobDetail = JobBuilder.newJob()// 创建一个jobbuilder用来定义一个任务明细。 .ofType(cls)// 设置类,将被实例化 .withIdentity(new JobKey(jobName, JOB_GROUP_NAME))// 使用给定的名称和默认组jobkey识别任务明细 .build();// 产品定义的JobDetail实例这jobbuilder。 Trigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule(time))// 设置schedulebuilder将用于定义触发器的表。 .withIdentity(new TriggerKey(jobName, TRIGGER_GROUP_NAME)).build();// 创建Trigger TriggerKey triggerKey = trigger.getKey(); JobKey jobKey = trigger.getJobKey(); // 把保存triggerKey和jobKey map.put("triggerKey", triggerKey); map.put("jobKey", jobKey); map.put("jobname", jobName); jobDetail.getJobDataMap().put("canshu", map); scheduler.scheduleJob(jobDetail, trigger);// 绑定 scheduler.start(); } catch (Exception e) { LOGGER.error("添加定时任务失败", e.getMessage()); throw new RuntimeException(e); } } /** * 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名) * * @param jobName * @param time
* @param map 业务参数,根据实际情况传参
*/ public void modifyJobTime(String jobName, String time, Map<String, Object> map, String jobkey, String triggerkey) { try { Trigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule(time))// 设置schedulebuilder将用于定义触发器的表。 .withIdentity(new TriggerKey(jobName, TRIGGER_GROUP_NAME)).build();// 创建Trigger if (trigger == null) { return; } removeJob(new TriggerKey(triggerkey), new JobKey(jobkey)); addJob(jobName, QuartzJob.class, time, map); } catch (Exception e) { LOGGER.error("添加定时任务失败", e.getMessage()); throw new RuntimeException(e); } } /** * 暂停一个任务(使用默认的任务组名,触发器名,触发器组名) * * @param triggerKey * @param jobKey */ public void pauseJob(TriggerKey triggerKey, JobKey jobKey) { try { scheduler.pauseTrigger(triggerKey);// 停止触发器 scheduler.pauseJob(jobKey); } catch (Exception e) { throw new RuntimeException(e); } } /** * 恢复一个任务(使用默认的任务组名,触发器名,触发器组名) * * @param triggerKey * @param jobKey */ public void resumeJob(TriggerKey triggerKey, JobKey jobKey) { try { scheduler.resumeTrigger(triggerKey); scheduler.resumeJob(jobKey); } catch (Exception e) { throw new RuntimeException(e); } } /** * 移除一个任务(使用默认的任务组名,触发器名,触发器组名) * * @param triggerKey * @param jobKey */ public void removeJob(TriggerKey triggerKey, JobKey jobKey) { try { scheduler.unscheduleJob(triggerKey);// 移除触发器 scheduler.deleteJob(jobKey); } catch (Exception e) { throw new RuntimeException(e); } } /** * 启动所有定时任务 */ public void startJobs() { try { Scheduler sched = schedulerFactory.getScheduler(); sched.start(); } catch (Exception e) { throw new RuntimeException(e); } } /** * 关闭所有定时任务 */ public void shutdownJobs() { try { Scheduler sched = schedulerFactory.getScheduler(); if (!sched.isShutdown()) { sched.shutdown(); } } catch (Exception e) { throw new RuntimeException(e); } } }
2. 备份集成到Quartz
创建QuartzJob类实现备份功能
/** * 任务类 */ @Service public class QuartzJob implements Job { @Autowired private BfbService bfbService; @Autowired private SjglSjbflbService sjglSjbflbService; @Autowired private SjglDsrwxxService sjglDsrwxxService; @Value("${dmdump.dev.password}") private String password; @Value("${dameng.dev.ip}") private String ip; @Value("${dameng.dev.userName}") private String userName; @Value("${dameng.dev.userPwd}") private String userPwd; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap map = context.getJobDetail().getJobDataMap(); Map<String, Object> data = (Map<String, Object>) map.get("canshu"); String copyType = data.get("copyType").toString(); System.out.println("备份地点:" + data.get("copyType")); // 拼接表名 String tnames = data.get("tnames"); String result = null; // 保存备份列表,备份文件名称=数据库id+T+时间 SjglSjbflbParam param = new SjglSjbflbParam(); param.setCjlx(copyType); // 获取服务器连接 if (data.get("ip") != null && data.get("port") != null && data.get("user") != null && data.get("pwd") != null && data.get("dir") != null) { param.setIp(data.get("ip").toString()); param.setPort(data.get("port").toString()); param.setUsername(data.get("user").toString()); param.setUsername(data.get("user").toString()); param.setRepassword(data.get("pwd").toString()); param.setDir(data.get("dir").toString()); } // 添加数据库备份列表数据 String fname = data.get("jobname").toString(); param.setDsrwxxid(Long.parseLong(fname.split("T")[0])); // param.setWjmc(fname); param.setCjz((Long) data.get("cjz")); StringBuffer tids = new StringBuffer(); for (String s1 : (String[]) data.get("ids")) { tids.append(s1).append(","); } param.setTids(tids.toString().substring(0, tids.toString().length() - 1)); param.setBflx("2"); String filename = sjglSjbflbService.add(param); // 修改任务表中的jobkey和triggerKey SjglDsrwxxParam dsparam = new SjglDsrwxxParam(); // 在定时任务表中添加keys字段 sjglDsrwxxService.updateKeyByid(Long.parseLong(fname.split("T")[0]), data.get("triggerKey").toString(), context.getJobDetail().getKey().toString()); // 获取服务器连接 Connection conn = DMruntimeUtil.login(ip, userName, userPwd); // 备份 if (copyType.equals("local")) { String dexpStr = DMruntimeUtil.dumpByTables(data.get("hostip").toString(), data.get("dbname").toString(), data.get("username").toString(), data.get("password").toString(), tnames, filename); String cmd = "cd /opt/dameng/dmdbms/bin;" + dexpStr; result = DMruntimeUtil.execute(conn, cmd); } else if (copyType.equals("foreignLands")) { // 调用shell脚本 sh dexplocal.sh test2 DEV.SYS_USER root@ip:/opt/data // pwd 22 String cmd = "sh /opt/dameng/dmdbms/shelldata/dexphand.sh " + filename + " " + tnames + " " + data.get("user") + "@" + data.get("ip") + ":" + data.get("dir") + " " + data.get("pwd") + " " + data.get("port"); result = DMruntimeUtil.execute(conn, cmd); } // return result; } }
通过linux脚本实现异地备份,也可通过拼接命令实现
#!/bin/bash //脚本声明 # 手动异城:方式备份EVAL.DEV数据 //注释信息 cd /opt/dameng/dmdbms/bin filename=$1 tables=$2 reurl=$3 password=$4 port=$5 ./dexp USERID=SYSDBA/SYSDBA@ip:port FILE=${filename}.dmp LOG=${filename}.log TABLES=${tables} DIRECTORY=/opt/dameng/dmdbms/dm7data/EVAL/dexp sshpass -p ${password} scp -P ${port} /opt/dameng/dmdbms/dm7data/EVAL/dexp/${filename}.dmp ${reurl}/${filename}.dmp echo "success"