最近写了一个MySQL数据库自动、手动备份管理系统开源项目,想跟大家分享一下,项目地址:https:gitee。comasurplusdbbackup1、界面献上 登录界面 首页 实例管理 执行备份 任务管理 备份记录 2、引入依赖!用于动态创建数据库连接dependencygroupIdcom。zaxxergroupIdHikariCPartifactIdversion4。0。3versiondependency!mysql连接驱动dependencygroupIdmysqlgroupIdmysqlconnectorjavaartifactIddependency!定时任务dependencygroupIdorg。springframework。bootgroupIdspringbootstarterquartzartifactIddependency!SaTokenQuickLogin插件dependencygroupIdcn。dev33groupIdsatokenquickloginartifactIdversion1。30。0versiondependency3、SaTokenQuickLogin快速登录插件 如果你开发了一个小系统,并不需要多用户登录,但是必须得有登录,你又不想写登录,那么用SaTokenQuickLogin快速登录插件是你的不二选择,具体用法参考:【SpringBoot】59、SpringBoot使用SaTokenQuickLogin插件快速登录认证https:lizhou。blog。csdn。netarticledetails1235719104、动态创建数据库连接1、拼接连接地址拼接urlparamhostparamportreturnpublicstaticStringgetUrl(Stringhost,Stringport,Stringdatabase){if(StringUtils。isBlank(database)){}returnjdbc:mysql:host:portdatabase?useUnicodetrueuseJDBCCompliantTimezoneShifttrueuseLegacyDatetimeCodefalseserverTimezoneAsiaShanghaiuseSSLtruecharacterEncodingUTF8;} 我们通过ip,端口就能动态创建数据库连接,因为每个数据库实例中都有mysql数据库,我们默认使用mysql数据库来创建连接2、获取数据库连接配置数据库连接配置paramproperties数据库连接信息returnpublicstaticHikariConfiggetHikariConfig(DbPropertiesproperties){HikariConfighikariConfignewHikariConfig();hikariConfig。setDriverClassName(properties。getClassName());hikariConfig。setJdbcUrl(getUrl(properties。getHost(),properties。getPort(),properties。getDatabase()));hikariConfig。setUsername(properties。getUsername());hikariConfig。setPassword(properties。getPassword());hikariConfig。setMaximumPoolSize(2);hikariConfig。setMinimumIdle(1);hikariConfig。setAutoCommit(true);hikariConfig。setConnectionTestQuery(SELECT1FROMDUAL);hikariConfig。addDataSourceProperty(cachePrepStmts,true);hikariConfig。addDataSourceProperty(prepStmtCacheSize,250);hikariConfig。addDataSourceProperty(prepStmtCacheSqlLimit,2048);returnhikariC}3、创建数据源创建数据源paramhikariConfigreturnpublicstaticHikariDataSourcecreateDataSource(HikariConfighikariConfig){if(nullhikariConfig){}returnnewHikariDataSource(hikariConfig);} 这样我们就能得到HikariDataSource数据源了,可以用来执行SQL语句,例如:查询实例中的数据库,查询数据库中的数据表,对数据表中的数据实现增删改查操作4、获取实例中的所有数据库获取数据库信息publicstaticListStringlistDataBases(DataSourcedataSource){try{JdbcTemplatejdbcTemplatenewJdbcTemplate(dataSource);ListStringdatabasesjdbcTemplate。query(SHOWDATABASES,newRowMapperString(){publicStringmapRow(ResultSetrs,introwNum)throwsSQLException{returnrs。getString(1);}},null);returnDbUtil。filterDatabase(databases);}catch(Exceptione){log。error(获取数据库信息失败:{},e。getMessage());}} 使用showdatabasesSQL语句,查询实例中的所有数据库信息,因为实例中包含MySQL的默认数据库,我们需要将其过滤掉,如下:privatestaticfinalListStringFILTERDATABASEArrays。asList(informationschema,mysql,performanceschema,sys);publicstaticListStringfilterDatabase(ListStringlist){if(CollectionUtil。isEmpty(list)){}ListStringresListnewArrayList();for(Stringitem:list){if(!FILTERDATABASE。contains(item)){resList。add(item);}}returnresL}5、获取数据库中的所有数据表获取数据表信息publicstaticListStringlistTables(DataSourcedataSource){try{JdbcTemplatejdbcTemplatenewJdbcTemplate(dataSource);ListStringdatabasesjdbcTemplate。query(SHOWTABLES;,newRowMapperString(){publicStringmapRow(ResultSetrs,introwNum)throwsSQLException{returnrs。getString(1);}},null);}catch(Exceptione){log。error(获取数据表信息失败:{},e。getMessage());}} 使用showtablesSQL语句,查询数据库中的所有数据表信息5、数据库备份1、公共参数项目路径publicstaticfinalStringPROJECTPATHSystem。getProperty(user。dir);当前系统类型publicstaticfinalStringOSNAMESystem。getProperty(os。name);2、拼接备份数据库命令拼接备份sql命令paramhost主机地址paramport端口paramdbName数据库名称paramtables表格名称paramdataType备份参数【0表结构1表数据else表结构表数据】paramusername用户名parampassword密码parampath备份文件目录paramfileName备份文件名returnpublicstaticString〔〕createBackupCommand(Stringhost,Stringport,StringdbName,String〔〕tables,IntegerdataType,Stringusername,Stringpassword,Stringpath,StringfileName){String〔〕commandsnewString〔3〕;if(OSNAME。startsWith(Win)){commands〔0〕cmd。commands〔1〕c;}else{commands〔0〕commands〔1〕c;}拼接命令StringBuildermysqldumpnewStringBuilder();mysqldump。append(mysqldump);mysqldump。append(opt);用户,密码mysqldump。append(user)。append(username);mysqldump。append(password)。append(password);ip,端口mysqldump。append(host)。append(host);mysqldump。append(port)。append(port);使用的连接协议,包括:tcp,socket,pipe,memorymysqldump。append(protocoltcp);设置默认字符集,默认值为utf8mysqldump。append(defaultcharactersetutf8);在导出数据之前提交一个BEGINSQL语句,BEGIN不会阻塞任何应用程序且能保证导出时数据库的一致性状态mysqldump。append(singletransactionTRUE);导出存储过程以及自定义函数mysqldump。append(routines);导出事件mysqldump。append(events);只备份表结构if(null!dataType){if(0dataType){mysqldump。append(nodata);}只备份表数据elseif(1dataType){mysqldump。append(nocreateinfo);}}数据库名mysqldump。append()。append(dbName);数据表名if(null!tables0tables。length){for(Stringitem:tables){mysqldump。append()。append(item);}}保存文件路径mysqldump。append()。append(path)。append(fileName);commands〔2〕mysqldump。toString();}3、执行备份数据库命令paramhost主机地址paramport端口paramdbName数据库名称paramtables表格名称paramdataType备份参数【0表结构1表数据else表结构表数据】paramusername用户名parampassword密码returnpublicBackRespVObackup(Stringhost,Stringport,StringdbName,String〔〕tables,IntegerdataType,Stringusername,Stringpassword){返回对象BackRespVOrespVOnewBackRespVO();try{当前年月日StringymdMysqlTool。getDate();文件目录StringpathPROJECTPATHFile。separatorstaticFile。separatorymdFile。文件名StringfileNameIdUtil。fastSimpleUUID()。创建文件FilefilenewFile(path,fileName);路径不存在,则新建if(!file。getParentFile()。exists()){file。getParentFile()。mkdirs();}shell命令脚本String〔〕commandscreateBackupCommand(host,port,dbName,tables,dataType,username,password,path,fileName);RuntimeruntimeRuntime。getRuntime();Processprocessruntime。exec(commands);备份成功if(process。waitFor()0){respVO。setFile(file);returnrespVO;}备份失败else{InputStreamisprocess。getErrorStream();if(is!null){BufferedReaderinnewBufferedReader(newInputStreamReader(is,OSNAME。startsWith(Win)?GBK:UTF8));SStringBuildersbnewStringBuilder();while((linein。readLine())!null){sb。append(line);}respVO。setMsg(【dbName】备份失败,原因:sb);respVO。setFile(file);}}}catch(Exceptione){respVO。setMsg(【dbName】备份失败,原因:e。getMessage());}returnrespVO;}4、执行备份任务,并保存备份记录异步执行备份任务,保存备份记录paramdbId实例idparamhost主机地址paramport端口paramdbName数据库名paramtables数据表名paramdataType备份参数【0表结构1表数据else表结构表数据】paramusername用户名parampassword密码paramstartTime开始时间paramcategoryEnum备份类型(手动备份,自动备份)AsyncpublicvoidsaveBackUp(IntegerdbId,Stringhost,Stringport,StringdbName,String〔〕tables,IntegerdataType,Stringusername,Stringpassword,DatestartTime,BackupCategoryEnumcategoryEnum){执行备份BackRespVOrespVObackup(host,port,dbName,tables,dataType,username,password);备份失败if(!respVO。isSuccess()){if(null!respVO。getFile()){respVO。getFile()。delete();}}保存备份记录BackupLogbackupLognewBackupLog();backupLog。setDbId(dbId);backupLog。setCategory(categoryEnum。getMsg());backupLog。setDatabaseName(dbName);backupLog。setTablesName(StringUtils。join(tables,,));backupLog。setDataType(dataType);backupLog。setStatus(respVO。isSuccess());backupLog。setMsg(respVO。getMsg());备份成功if(respVO。isSuccess()){文件相对路径backupLog。setFilePath(respVO。getFile()。getPath()。replace(MysqlTool。PROJECTPATHFile。separator,));backupLog。setFileSize(respVO。getFile()。length());}开始时间backupLog。setStartTime(startTime);backupLog。setEndTime(newDate());backupLog。setSpendTime(backupLog。getEndTime()。getTime()backupLog。getStartTime()。getTime());backupLogMapper。insert(backupLog);} 我们采用异步执行的方式,因为备份过程可能会很漫长,执行备份了之后,得到备份的文件路径,保存在备份记录中,可以实时进行查看6、添加自动备份定时任务 定时任务主要依赖quartz,可以动态管理定时任务,非常方便1、定时任务管理工具类importcn。hutool。core。collection。CollectionUimportcom。asurplus。entity。BackupTimportcom。asurplus。mapper。BackupTaskMimportlombok。extern。slf4j。Slf4j;importorg。quartz。;importorg。springframework。beans。factory。annotation。Aimportorg。springframework。stereotype。Cimportjavax。annotation。PostCimportjavax。annotation。Rimportjava。util。Lquartz工具类AuthorAsurplusSlf4jComponentpublicclassQuartzManager{参数传递keypublicstaticfinalStringPARAMKEY执行任务类名publicstaticfinalStringCLASSNAMEcom。asurplus。job。DbBackupJ程序调度器AutowiredprivateSResourceprivateBackupTaskMapperbackupTaskM系统启动执行PostConstructpublicvoidinit(){ListBackupTasklistbackupTaskMapper。selectList(null);if(CollectionUtil。isNotEmpty(list)){for(BackupTaskitem:list){try{add(item。getId(),item。getCron(),item。getParam(),item。getStatus());}catch(Exceptione){log。error(e。getMessage());}}}}添加定时任务publicvoidadd(Integerid,StringcronExpression,Stringparam,Booleanstatus){try{构建job信息JobDetailjobDetailJobBuilder。newJob(getClass(CLASSNAME)。getClass())。withIdentity(getKey(id))。usingJobData(PARAMKEY,param)。build();表达式调度构建器(即任务执行的时间)CronScheduleBuilderscheduleBuilderCronScheduleBuilder。cronSchedule(cronExpression);按新的cronExpression表达式构建一个新的triggerCronTriggertriggerTriggerBuilder。newTrigger()。withIdentity(getKey(id))。withSchedule(scheduleBuilder)。build();创建定时任务scheduler。scheduleJob(jobDetail,trigger);停止if(!status){stop(id);}}catch(Exceptione){log。error(添加定时任务失败:{},e。getMessage());}}编辑定时任务publicvoidupdate(Integerid,StringcronExpression,Stringparam,Booleanstatus){try{判断是否存在,存在先删除if(scheduler。checkExists(JobKey。jobKey(getKey(id)))){scheduler。deleteJob(JobKey。jobKey(getKey(id)));}再创建add(id,cronExpression,param,status);}catch(Exceptione){log。error(修改定时任务失败:{},e。getMessage());}}暂停任务publicvoidstop(Integerid){try{scheduler。pauseJob(JobKey。jobKey(getKey(id)));}catch(SchedulerExceptione){暂停定时任务失败log。error(暂停定时任务失败:{},e。getMessage());}}恢复任务publicvoidstart(Integerid){try{scheduler。resumeJob(JobKey。jobKey(getKey(id)));}catch(SchedulerExceptione){暂停定时任务失败log。error(启动定时任务失败:{},e。getMessage());}}立即执行一次publicvoidrun(Integerid){try{scheduler。triggerJob(JobKey。jobKey(getKey(id)));}catch(SchedulerExceptione){暂停定时任务失败log。error(执行定时任务失败:{},e。getMessage());}}删除定时任务publicvoiddelete(Integerid){try{停止触发器scheduler。pauseTrigger(TriggerKey。triggerKey(getKey(id)));移除触发器scheduler。unscheduleJob(TriggerKey。triggerKey(getKey(id)));删除任务scheduler。deleteJob(JobKey。jobKey(getKey(id)));}catch(Exceptione){log。error(删除定时任务失败:{},e。getMessage());}}根据类名获取类privateJobgetClass(StringclassName)throwsException{C?class1Class。forName(className);return(Job)class1。newInstance();}拼接keyreturnpublicStringgetKey(Integerid){returndbBackU}} 包含对定时任务的增删改查操作,默认执行job为:com。asurplus。job。DbBackupJob 2、备份任务importcom。alibaba。fastjson。JSONOimportcom。asurplus。config。quartz。QuartzMimportcom。asurplus。enums。BackupCategoryEimportcom。asurplus。utils。MysqlTimportcom。asurplus。vo。BackupJobVO;importlombok。extern。slf4j。Slf4j;importorg。quartz。Jimportorg。quartz。JobExecutionCimportorg。quartz。JobExecutionEimportorg。springframework。beans。factory。annotation。Aimportjava。util。D备份定时任务Slf4jpublicclassDbBackupJobimplementsJob{AutowiredprivateMysqlToolmysqlTOverridepublicvoidexecute(JobExecutionContextcontext)throwsJobExecutionException{解析参数BackupJobVOvoJSONObject。parseObject(context。getJobDetail()。getJobDataMap()。getString(QuartzManager。PARAMKEY),BackupJobVO。class);开始备份mysqlTool。saveBackUp(vo。getDbId(),vo。getHost(),vo。getPort(),vo。getDbName(),vo。getTables(),vo。getDataType(),vo。getUsername(),vo。getPassword(),newDate(),BackupCategoryEnum。AUTO);}} 获取到备份参数,包括:主机地址,端口,用户名,密码,数据库名等,就能执行备份任务了 好了,我们的数据库备份管理系统大致就介绍完了,如您在阅读中发现不足,欢迎留言!!!