spring boot 数据库抽取数据表中字段可配置性及增量抽取

前言:基于项目的需要抽取目标源数据库中,其中表名和数据库字段需要可配置,并能实现增量更新。自创文档大佬们不喜勿喷。

一、数据的抽取及字段的可配置

1、简单的数据抽取

     最简单的数据抽取就是把目标源中所需要的数据抽取到自己的数据库中。只要知道数据库表中的字段然后select、insert就OK了

2、可配置字段的数据抽取

(1)自定义配置文件

因为项目的需求,无法确定目标源中表中字段是我们所需要的,如果代码中写死,后期可能需要改动代码,所以此处把代码写灵活一点避免后期频繁的改动代码。

Spring boot 的经常用到的配置文件是application.yml 或是application.properties,此处我用的是application.yml。

两种配置文件的区别请参考:

 https://blog.csdn.net/weixin_30666943/article/details/97737922?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158501880219724847036587%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158501880219724847036587&biz_id=0&utm_source=distribute.pc_search_result.none-task

这里自定义配置文件: dbConfig.properties

在自定义配置文件中定义号自己要抽取目标源表的表名,字段名。

然后用PropertiesUtil类去获取配置文件中的信息。

package com.bug.demo.util;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Properties;

代码如下:
/**
 * @author bughuang
 * @version 1.0
 * @date 2020/3/16 12:32
 */
public class PropertiesUtil {
    private static Logger log = LoggerFactory.getLogger(PropertiesUtil.class);
    private static Properties props;


    //resource文件夹内读取
    static {
        String fileName = "dbConfig.properties";
        props = new Properties();
        try {
            props.load(new InputStreamReader(Objects.requireNonNull(PropertiesUtil.class.getClassLoader().
                    getResourceAsStream(fileName)), StandardCharsets.UTF_8));
        } catch (IOException e) {
            log.error("配置文件读取异常", e);
        }
    }

    /**
     * 根据配置文件中的key获取value
     * @param key
     * @return
     */
    public static String getProperty(String key) {
        String value = props.getProperty(key.trim());
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        return value.trim();
    }

    /**
     * 根据配置文件中的key获取value (当获取不到值赋予默认值)
     * @param key
     * @param defaultValue
     * @return
     */
    public static String getProperty(String key, String defaultValue) {
        String value = props.getProperty(key.trim());
        if (StringUtils.isEmpty(value)) {
            value = defaultValue;
        }
        return value.trim();
    }

}

自定义配置文件及如何获取内容:

https://blog.csdn.net/qq_35387940/article/details/90714123

另外也可以通过自定义.yml文件用注解读取如:

 https://blog.csdn.net/tyrant_800/article/details/78780312?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158497595819724848305578%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158497595819724848305578&biz_id=0&utm_source=distribute.pc_search_result.none-task

这里就不再多叙述了。

(2)mybatis 用参数传递查询与插入

 <select id="queryPeopleInfoByColumn" resultType="java.util.Map">
         select a.${userName},
                a.${idA},
               a.${sex},
               a.${age},
               a.${phone},
               a.${email},
               b.${unitName},
               c.${dutyName}
        from ${tableA} a
                 LEFT JOIN ${tableB} b on a.${idA} = b.${unitPkey}
                 LEFT JOIN ${tableC} c on c.${dutyPkey} = a.${idA}
        WHERE a.${userName} != ''
   </select>

 

 <insert id="insertPeople" parameterType="java.util.List" useGeneratedKeys="true"
            keyProperty="id">
        <selectKey keyProperty="id" resultType="java.lang.Integer" order="BEFORE">
            SELECT nextval('USER_SEQ_ID')
        </selectKey>
        insert into target (id,user_name,sex,age,phone,email,unit_name,duty_name,user_id,insert_time)
        values
        <foreach collection="list" index="index" item="item" separator=",">
            (nextval('USER_SEQ_ID'),
            #{item.userName,jdbcType=VARCHAR},
            #{item.sex,jdbcType=VARCHAR},
            #{item.age,jdbcType=VARCHAR},
            #{item.phone,jdbcType=VARCHAR},
            #{item.email,jdbcType=VARCHAR},
            #{item.unitName,jdbcType=VARCHAR},
            #{item.dutyName,jdbcType=VARCHAR},
            #{item.userId,jdbcType=VARCHAR},
            #{item.insertTime,jdbcType=VARCHAR})
        </foreach>
 </insert>

这样可以解决字段名改变只需要修改配置文件就可以抽取一个表中其他字段。

注意:这里必须是抽取的结果集一定,就是想要的字段数量固定。但如果一旦表中的关联关系改变就无法满足。 此时就可以在配置文件中加入sql语句,然后mybatis中传递sql。还是要注意结果集必须是确定的。

 

  <select id="queryPeopleInfoBySql" resultType="java.util.Map">
       ${sql}
  </select>

(3)抽取结果

现在我改变了配置文件中的配置:

 

然后执行得到:

3、增量抽取

以上两个步骤可以完成批量的抽取,但是在项目中有时需要增量抽取数据入库。

项目中用的数据库是postgresql,网上查看的增量抽取的方法都需要在源数据库上安装插件。这里不符合项目情况,所以只能自己开发。此下的方法应该适合所有的数据库。

(1)创建log表记录抽取记录

       表结构如下:

(2)插入之前查询log表

每次需要更新数据的时候查询一下log表如果表中没有该张表的数据,则是批量插入,如果有就是增量插入。如果是增量插入需要根据Log表中存储的data_type 判断是时间还是根据id。然后出最后一条记录,取出data_index的值。更具data_index的值在查询的时候增加查询条件。

<select id="queryPeopleInfoIncreaseByColumnAndId" resultType="java.util.Map">
       select a.${userName},
               a.${sex},
               a.${age},
               a.${phone},
               a.${email},
               b.${unitName},
               c.${dutyName}
        from ${tableA} a
                 LEFT JOIN ${tableB} b on a.${idA} = b.${unitPkey}
                 LEFT JOIN ${tableC} c on c.${dutyPkey} = a.${idA}
        WHERE a.${userName} != '' and to_number(a.${idA},'9999999999999999999') > ${dataIndex}
 </select>

(3)插入之后更新log表

  每次根据源数据库跟新数据到自己的数据库中,数据更新完毕时插入数据到Log中记录插入的时间及表名等信息。

<insert id="insert" parameterType="com.bug.demo.domain.DataLog" useGeneratedKeys="true"
            keyProperty="id">
    <selectKey keyProperty="id" resultType="java.lang.Integer" order="BEFORE">
            SELECT nextval('LOG_SEQ_ID')
    </selectKey>
     insert into t_data_log (id, data_type, data_index,
     update_time, is_delete,table_name)
     values (nextval('LOG_SEQ_ID'), 
    #{dataType,jdbcType=VARCHAR}, #{dataIndex,jdbcType=VARCHAR}, 
    #{updateTime,jdbcType=VARCHAR}, #{isDelete,jdbcType=VARCHAR},
    #{tableName,jdbcType=VARCHAR})
</insert>

4、设置定时任务

设置定时任务每5分钟执行一次。

设置定时任务的步骤如下:

(1)在启动类中加入:

@EnableScheduling

@EnableAsync

 

(2)创建任务类

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author bughuang
 * @version 1.0
 * @date 2020/3/19 17:42
 */
@Component
@Slf4j
public class AsyncTask {
    @Resource
    private EtlController etlController;

    @Scheduled(cron = "${cron}")
    //定时任务需要返回值的情况
    public void task4() {
        long begin = System.currentTimeMillis();
        ResultModel resultModel = etlController.EtlTest();
        long end = System.currentTimeMillis();
        log.info("任务查询更新数据耗时="+(end-begin)+"结果是:"+resultModel);
    }

}

并加上@ Component

(3)设置任务开始时间

@Scheduled(cron = "${cron}")

Spring boot 定时任务请参考:

https://blog.csdn.net/qq_32120667/article/details/96477237?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158504116719726867834561%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158504116719726867834561&biz_id=0&utm_source=distribute.pc_search_result.none-task

结束语:需要代码的请联系我。。

 

发布了2 篇原创文章 · 获赞 0 · 访问量 73
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览