数据导入,绝对的干活
有很多项目都存在数据导入的情况,我们项目其中一个数据导入是门店信息导入,大家可以借鉴参考一下
1.得有一张记录文件导入信息的表,首先是重点几个字段,文件的id,文件的类型,文件的状态,这三点是最关键的(其实应该还有一个文件存放的路径,但我们项目里是采取拼接的方法将其更新到主键),还有其他几个字段,文件名称,创建时间,创建人这些比较次之,至于还需要别的字段,可根据自己业务进行拓展
2.文件导入进来,需要存放到我们系统的一个位置,这里的位置一般都是写成配置的,在配置文件里面配置
3.这点比较关键,需要一个redis的分布式锁,需要设置key,过期时间,这么做的目的是防止一个用户进行多次文件上传的操作
4.开始处理excel里面导入的数据,这里有个阿里巴巴包里面的BaseRowModel类,这个是excel基础模型,我们可以用一个我们的业务类去继承它,我们这里是StoreExcel类,这个类里面可以定义索引对应哪个值,比如第一列
对应门店的名称,可采取@ExcelProperty(index=1)这样一个注解,通过stream流的形式去读数据,每一行即是一个对象,这个时候我们需要有一张门店附表,这个门店附表的结构和门店主表的结构差不多,但是会多几个字段,文件的id,代表这个门店数据是哪个文件里面的,状态代表这个门店是否成功等,行数代表是文件里面哪一行的数据,当然这里会存在一个优化的操作,可能一个excel里面会有很多数据,我们可以采取分批数据,十个十个一批,具体的批次大小可采取配置的形式
5.数据处理完了,此时我们的文件导入信息表,门店附表都有数据了,这个时候我们就要为异步处理做准备了,我们需要一个StoreJobMessage表,这个表需要的字段有优先级,文件id代表是哪个文件的job,jobType代表是哪个类型,这个后面会提到,表记录完了,需要进行异步注册任务了,我们项目有一个quartrz,这个模块是专门为定时任务准备的,但是门店是在store模块,所以我们需要通过RestTemplate去调用quartrz模块对应的接口,这个接口调用成功了,我们就可以返回给前端了,说处理成功了
6.这个时候前端页面是没有操作,剩下的就是后端进行了,上面说到调用quartrz模块注册任务的接口,这里其实是向一张JobLog表插入记录,将前面的jobId以及一个待执行的状态等有关信息插入到这种表里,表示这条记录执行的是哪个任务,等插入完之后,quartrz模块有个类里面的run会去扫描这个JobLog表,判断这个任务是不是待执行的,是就处理这个任务,不是则不处理,当然这个需要捕获异常,可能会存在线程池队列满了,这个时候就需要将任务重新放回去,将其状态还是改成待执行,失败次数不增加,这个失败次数是方便以后查问题时排查的,还可能出现另一种异常,也要做捕获处理,当一个任务一直执行失败,并且超过了最大次数,这个最大失败次数要写成配置,就不去处理了,将其状态改成失败,最后设置这个run方法里面设置一个睡眠时间,等待多少秒之后在重新扫描,接下里说一下怎么处理这个任务,这个任务会去调用一个方法,这个方法有个@async,这个注解是将这个方法交给线程池执行,所以才会出现线程池满了抛了异常需要捕获的这个场景,这个方法里面的第一步操作就需要前面说的job类型了,我们得根据不同的类型去调用不同的接口,这个时候呢我们就需要一张映射表,这个映射表里面会记录job类型,这个类型对应的类,接口路径等字段,拿到对应的接口路径了,就还是一样,通过RestTemplate去调用store模块里面的接口,就又回到了store模块,然后执行完之后更新这个任务的状态。
7.我们又回到store模块之后,此时我们已经知道了这个任务对应的接口了,找到具体的文件导入的方法就行,这个时候建议有个抽象类,里面有个进程的方法,方便拓展,一个系统不可能只要一个数据导入的地方,就算目前就一个,后续可能会增加,有了这个抽象类,我们就可以用一个业务类去继承他,然后实现里面的方法,如果后续别的也需要,那么它只要继承这个类实现其方法就行,这个方法里面调用的就是其具体的实现方法了,剩下的就是将门店数据处理了,该校验的校验,校验通过的就存到主表里面去,更新一下附表的状态,还有文件导入信息的状态,这个流程就走完了
8.补充一点,前面说的quartrz模块里面处理任务的方法上面有个@Async注解,这个是线程池,得有一个bean对象才行,我们会有一个线程池的配置类ThreadConfig,里面会有一个方法,这个方法的名称就是那个@Async注解里面的value值,在这个方法上面有个@bean注解,在这里面定义一个ThreadPoolTaskExecuter类,配置好相关的线程池参数即可,最后返回,交给spring处理
绝对的干货,太不容易了,不过后续都可套用