日志数据在很多行业中都是非常敏感的数据,它们不能删除只能保存和查看,这样日志表就会越来越大,我们不可能永远让它无限制的增长下去,必须采取一种手段将数据分散开来。假设现在整个数据库需要保存的数据量比较少,但是只有日志表的数据量会很大,在这种情况下我们可以考虑使用分表策略分散保存日志数据。
针对当前系统来讲,可以这么做:每个月创建一张新表用于保存当月的日志数据。当然这只是初期的保存日志的思路。
1.解决问题的方法就是分表,那么什么时候创建新表呢?
(1).如果服务器不关闭,假设一直处于运行状态,每个月的月末创建下一个月的日志表好像是比较不错的,但是这和软件测试的边界值条件相符合,是非常容易出错的地方,所以,在每个月的中间创建新表是比较不错的选择;处于系统的健壮性考虑,创建接下来两个月的表是比较合适的。
(2).当前月的表如何创建。
服务器不可能一开始就是开启的,所以我们需要在服务器开启的时候就创建好当前月的日志表,但是只是创建当前月的日志表还是不够的,还需要创建接下来两个月使用的日志表,或许你会问为什么,之后就交给某个定时器每个月中间自动创建表不就可以了吗?但是你没有考虑到,如果服务器的启动时间正好是在一个月的下半个月怎么办?这时候到了下个月的时候就没有日志表可用了。
2.接下来还有问题就是怎么将日志信息保存到当前月的日志表
这个实际上是比较简单的,我们通过一个规则根据时间动态的指定创建的表名,同样在插入数据的时候也能够使用相同的规则插入到当前月的表中。
3.怎么将数据从多个表中取出来
使用sql的union连接查询即可达到目的。
二、使用spring的石英调度定时创建日志表
使用spring石英调度任务的步骤如下:
1.创建石英调度任务类
该类必须继承org.springframework.scheduling.quartz.QuartzJobBean抽象类并重写executeInternal方法
1 package com.kdyzm.schedual; 2 3 import org.quartz.JobExecutionContext; 4 import org.quartz.JobExecutionException; 5 import org.springframework.scheduling.quartz.QuartzJobBean; 6 7 import com.kdyzm.service.LogService; 8 import com.kdyzm.utils.LogUtils; 9 /** 10 * 创建的石英任务:使用spring集成的石英调度,动态生成日志表 11 * @author kdyzm 12 * 13 */ 14 public class GenerateLogsTableTask extends QuartzJobBean{ 15 private LogService logService; 16 public LogService getLogService() { 17 return logService; 18 } 19 public void setLogService(LogService logService) { 20 this.logService = logService; 21 } 22 /** 23 * 执行调度任务的方法 24 * 每月15号创建下两个月需要用到的日志表 25 */ 26 @Override 27 protected void executeInternal(JobExecutionContext context) throws JobExecutionException { 28 String tableName=LogUtils.createGenerateLogsTableName(1); 29 String sql="create table if not exists "+tableName+" like logs"; 30 this.logService.executeSql(sql); 31 System.out.println(tableName+" 表生成了!"); 32 tableName=LogUtils.createGenerateLogsTableName(2); 33 sql="create table if not exists "+tableName+" like logs"; 34 this.logService.executeSql(sql); 35 System.out.println(tableName+" 表生成了!"); 36 } 37 }
这里需要创建一个LogUtils工具类并且封装一个生成日志表名的方法:该方法的参数是一个偏移量,如果是整数表示下几个月,如果是负数表示是上几个月,使用Calendar类给出的方法能够非常快速的计算出来加上几个月或者减去几个月之后的日期。
1 package com.kdyzm.utils; 2 3 import java.util.Calendar; 4 5 /** 6 * 专门针对日志生成流程定义的工具类 7 * @author kdyzm 8 * 9 */ 10 public class LogUtils { 11 //动态生成日志表名的方法 12 public static String createGenerateLogsTableName(int offset){ 13 Calendar calendar=Calendar.getInstance(); 14 // month=(month+offset-1)%month+1; 15 //计算偏移之后的动态表名 16 calendar.add(Calendar.MONTH, offset); 17 int year=calendar.get(Calendar.YEAR); 18 int month=calendar.get(Calendar.MONTH)+1; 19 return "logs_"+year+"_"+month; 20 } 21 }
2.配置applicationConext.xml
为了更加清晰的完成该项任务,单独使用一个配置文件完成该项任务的配置。
配置步骤:
(1)使用org.springframework.scheduling.quartz.JobDetailBean封装石英任务
1 <bean id="jobDetailBean" class="org.springframework.scheduling.quartz.JobDetailBean"> 2 <property name="jobClass" value="com.kdyzm.schedual.GenerateLogsTableTask"></property> 3 <!-- 通过spring管理的bean必须通过这种方式注入到schema中 --> 4 <property name="jobDataAsMap"> 5 <map> 6 <entry key="logService" value-ref="logService"></entry> 7 </map> 8 </property> 9 </bean>
(2)设置触发器Bean,设置任务的调度策略
1 <!-- 触发器bean,设置任务的调度策略 --> 2 <bean id="cronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean"> 3 <property name="jobDetail" ref="jobDetailBean"></property> 4 <property name="cronExpression"> 5 <!-- 这个表达式的意思是:每个月的15号 --> 6 <value>0 0 0 15 * ? *</value> 7 </property> 8 </bean>
这里cronExpression中的值怎么填写是比较重要的,这里有7个参数需要填写,必须明白这七个参数的意思是什么
这七个参数分别对应着 [秒] [分] [小时] [日] [月] [周] [年]
其中"日"和"周"两个字段是相互对立的两个字段,"日"值的是一个月的几号,"周"指的是一周的星期几,两者是"有你无我"的立场。
|
序号 |
说明 |
是否必填 |
允许填写的值 |
允许的通配符 |
|
1 |
秒 |
是 |
0-59 |
, - * / |
|
2 |
分 |
是 |
0-59 |
, - * / |
|
3 |
小时 |
是 |
0-23 |
, - * / |
|
4 |
日 |
是 |
1-31 |
, - * ? / L W |
|
5 |
月 |
是 |
1-12 or JAN-DEC |
, - * / |
|
6 |
周 |
是 |
1-7 or SUN-SAT |
, - * ? / L # |
|
7 |
年 |
否 |
empty 或 1970-2099 |
, - * / |
(3)使用调度工厂bean激活触发器,启动石英任务
1 <!-- 调度器工厂bean,激活触发器,启动石英任务的 --> 2 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 3 <property name="triggers"> 4 <ref bean="cronTriggerBean"/> 5 </property> 6 </bean>
从上述三个步骤来看,后一个步骤依次对前面的任务进行了封装。
完整的schedual.xml配置文件:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 4 xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/beans/spring-beans-2.5.xsd 6 http://www.springframework.org/schema/context file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/context/spring-context-2.5.xsd 7 http://www.springframework.org/schema/aop file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/aop/spring-aop-2.5.xsd 8 http://www.springframework.org/schema/tx file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/tx/spring-tx-2.5.xsd"> 9 <!-- 配置调度任务的spring配置文件 --> 10 11 <!-- 任务明细bean,对石英任务进行封装 --> 12 <bean id="jobDetailBean" class="org.springframework.scheduling.quartz.JobDetailBean"> 13 <property name="jobClass" value="com.kdyzm.schedual.GenerateLogsTableTask"></property> 14 <!-- 通过spring管理的bean必须通过这种方式注入到schema中 --> 15 <property name="jobDataAsMap"> 16 <map> 17 <entry key="logService" value-ref="logService"></entry> 18 </map> 19 </property> 20 </bean> 21 <!-- 触发器bean,设置任务的调度策略 --> 22 <bean id="cronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean"> 23 <property name="jobDetail" ref="jobDetailBean"></property> 24 <property name="cronExpression"> 25 <!-- 这个表达式的意思是:每个月的15号 --> 26 <value>0 0 0 15 * ? *</value> 27 </property> 28 </bean> 29 <!-- 调度器工厂bean,激活触发器,启动石英任务的 --> 30 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 31 <property name="triggers"> 32 <ref bean="cronTriggerBean"/> 33 </property> 34 </bean> 35 </beans>