基于子公司与总公司同步数据问题

由于有多个数据源,所以我们首先需要对数据源进行一个管理。

同时由于我们也是多数据导入,我们也需要一个进度条那么就需要作业调度。那么多线程并发访问问题就会出现。(LocalThread,并对资源进行一个上锁)

关于总部的数据源我们使用阿里的Druid进行管理,这就是一个数据源连接池,附加了很多功能(sql监控等),并对性能进行优化。


我们会把所有的数据源进行管理,放入map然后获取

private Map<String, DataSource>  dataSourceCache;

之后我们需要对每个数据源添加事务,之后,进行管理

      DataSourceTransactionManager tm = new DataSourceTransactionManager(ds);
      DefaultTransactionDefinition td = new DefaultTransactionDefinition();
      td.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
      td.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
      dataSourceCache.put(ds, new TransactionTemplate(tm, td));

这是获取数据源的问题解决了。

那么接下来就是对资源进行一个上锁,资源就是我们要执行的job
我们可以自定义上锁资源。

我们可以创建一个表,用来存储资源id等数据,设置资源id为主键,只要我们save这个表对象的时候,如果被锁,那么insert就会报错,那么证明该资源已被锁。

if (lock == null) {
      lock = new PDataSyncLock();
      lock.setExpiredTime(DateUtils.addSeconds(now, continuingSeconds));
      try {
        em.persist(lock);
        em.flush();
      } catch (PersistenceException e) {
        throw new LockException("资源“{0}”已被锁定。", resource);
      }
    } else if (lock.getExpiredTime().compareTo(now) <= 0) {
      em.merge(lock);
      em.flush();

    } else {
      throw new LockException("资源“{0}”已被锁定。", resource);
    }

将资源锁定之后,那么开始执行数据同步.
pentaho的Kettle的开源ETL工具

进行数据同步我们使用的是pentaho的Kettle的开源ETL工具,允许你管理来自不同数据库的数据。拥有可视化工具。

主要有2个脚本文件,transformation(对数据的基础转换)和job(整个工作流的控制)

public KettleTransBuilder(String name) {
    try {
      String kettleHome = KettleTransBuilder.class.getResource("/").getFile() + "../../kettleLog";  //之后创建转换对象,这里指定转换文件的位置
      // 获得执行类的当前路径
      String user_dir = System.getProperty("user.dir");
      // Kettle初始化需要修改相应的配置路径
      System.setProperty("KETTLE_HOME", kettleHome);
      System.setProperty("user.dir", kettleHome);
      // 运行环境初始化(设置主目录、注册必须的插件等)  初始化kettle环境
      KettleEnvironment.init();
      // Kettle初始化完毕,还原执行类的当前路径    对于web项目要这样换一下路径,否则第一次加载要好久
      System.setProperty("user.dir", user_dir);
      //创建ktr元对象      
      transMeta = new TransMeta();
      transMeta.setName(name);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
Trans trans = new Trans(transMeta);    之后调用trans.setParameterValue("FILE_PATH",读入文件的路径比如excel文件路径)

该类是我们封装的一个类。其中包含很多外观方法,将很多kettle繁琐的步骤,组合在一起(外观模式)。

比如:我们同步数据的时候,是从总部数据库,直接全部拉下来。 所以需要在子库,全部删除。我们就需要直接执行sql语句。

通过ExecSQLMeta这个类,它被提供就是用来执行sql的。

 // 构造执行脚本步骤
    ExecSQLMeta execMeta = new ExecSQLMeta();
    String pluginId = PluginRegistry.getInstance().getPluginId(StepPluginType.class, execMeta);
    execMeta.setDatabaseMeta(transMeta.findDatabase(dsName));
    execMeta.setSql(sql);
    execMeta.setSingleStatement(singleStatement);
    execMeta.setVariableReplacementActive(true);
之后在执行的时候

 StepMeta execStep = new StepMeta(pluginId, STEP_EXECSQL + "_" + index, execMeta);
     transMeta.addStep(execStep);
这就相当于一个作业的监控,按步执行,进行一个进度监控。将每一步,传入job

但是同步数据,也就是insert,和select数据。

insert,通过调用TableInputMeta类。select同理 使用 TableOutputMeta。删除,DeleteMeta类

public KettleTransBuilder inputData(String dsName, String sql) {
    Assert.assertArgumentNotNull(dsName, "dsName");
    Assert.assertArgumentNotNull(sql, "sql");

    TableInputMeta tableInput = new TableInputMeta();
    String pluginId = PluginRegistry.getInstance().getPluginId(StepPluginType.class, tableInput);
    DatabaseMeta dsMeta = transMeta.findDatabase(dsName);
    tableInput.setDatabaseMeta(dsMeta);
    tableInput.setSQL(sql);
    tableInput.setVariableReplacementActive(true);
    if (!transMeta.getSteps().isEmpty()) {
      StepMeta preStep = transMeta.getSteps().get(transMeta.getSteps().size() - 1);
      if (preStep.getName().startsWith(STEP_INPUTTIMESTAMP)) {
        // 时间戳不为空
        tableInput.setLookupFromStep(preStep);
      }
    }

    List<StepMeta> inputSteps = getStepMega(transMeta.getSteps(), STEP_INPUTDATA);
    String index = String.valueOf(inputSteps.size() + 1);
    StepMeta inputDataStep = new StepMeta(pluginId, STEP_INPUTDATA + "_" + index, tableInput);
    transMeta.addStep(inputDataStep);

    return this;
  }








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值