java-不同库之间的数据迁移

9 篇文章 0 订阅
5 篇文章 0 订阅

背景

项目开发完成上线或投入生产后,会生成大量数据,针对数据安全考虑大多会进行数据的备份,有的人工操作有的自动备份;
我这边根据需求,客户要求将一些表的数据备份到我们这边的服务器上
当然目前我还处于项目熟悉阶段,可能理解的有所偏差

功能描述

可配置两个(或多个,根据需求)不同的数据库,对其中一些表的数据进行数据迁移,并且可以对原表进行标记(是否已迁移等),也可以对某些数据进行修改——比如将创建时间改为当前时间等(根据实际需求);
开放接口,可以按需求由前端或人工调用,对其它表也能进行数据迁移操作;
可配置定时任务和频率,自动执行数据迁移操作;

上代码

目录结构

在这里插入图片描述

controller

存放控制器,对外开放访问接口,尽可能只编写主要逻辑,具体实现交给service层

service、mapper

存放服务实现和映射(操作数据库),service负责业务功能的具体实现,需要与数据库交互时在mapper层编写响应的接口

vo

存放自定义JavaBean,根据业务需求为了方便参数的传递而创建的自定义JavaBean

application.yml

启动配置类,同时也存放数据迁移所需的一些配置,如接收、发送者数据库连接信息和定期任务等

properties

存放对配置文件的读取类,使用配置文件保存配置信息,对于使用者来说远比根据需求传入一堆参数更友好

配置信息

server:
  port: 9020
# 配置定时任务执行时间(cron表达式)
schedules:
  # 目前默认执行频率为每分钟一次
  runBatch: 0 0/1 * * * ?
# 数据转移参数
transfer:
  # 发送者数据库地址
  sendUrl: jdbc:mysql://地址:端口/数据库?useUnicode=true&characterEncoding=utf8
  # 发送者数据库用户名
  sendName: 用户名
  # 发送者数据库密码
  sendPassword: 密码
  # 发送者数据库查询语句
  # tableName为表名全称,shortName为表名简称——非必要不用动
  sendSql: select * from tableName where shortName_flag_state != '删除'
  # 接收者数据库地址
  acceptUrl: jdbc:mysql://地址:端口/数据库?useUnicode=true&characterEncoding=utf8
  # 接收者数据库用户名
  acceptName: 用户名
  # 接收者数据库密码
  acceptPassword: 密码
  # 需要修改值的列名
  # shortName为表名简称——非必要不用动
  updateColumn: shortName_flag_state
  # 需要修改为的值
  updateString: 删除
  # 是否开启定时转移任务
  # 只有配置值为 true 时开启定时任务
  schedule: false
spring:
  application:
    name: transfer         #服务名
  # 接收者數據庫信息
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://地址:端口/数据库?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    username: 用户名
    password: 密码

依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

核心代码

TransferController
package com.rongyi.transfer.controller;

import com.rongyi.transfer.properties.ApplicationProperties;
import com.rongyi.transfer.service.TransferService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.sql.*;

@Component
@RestController
@RequestMapping("/transfer")
public class TransferController {
    @Autowired
    private ApplicationProperties properties;

    @Autowired
    private TransferService transferService;

	// 定时遍历迁移
    @Scheduled(cron="${schedules.runBatch}")
    public void scheduledMove() throws SQLException {
        if (properties.getSchedule() != null && "true".equals(properties.getSchedule())) {
            String[] shortNames = {"c01", "i02", "w03"};
            for (String shortName : shortNames) {
                moveTable(shortName);
            }
            System.out.println("本次定时任务执行完毕");
        }
    }

	// 迁移
    @GetMapping("/moveTable/{shortName}")
    public String moveTable(@PathVariable("shortName") String shortName) throws SQLException {
        transferService.moveCustom(shortName);
        return shortName + "迁移完成";
    }
}

TransferService
package com.rongyi.transfer.service;

import com.rongyi.transfer.mapper.TransferMapper;
import com.rongyi.transfer.properties.ApplicationProperties;
import com.rongyi.transfer.vo.InsertVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.sql.*;

@Service
public class TransferService {
    @Resource
    private TransferMapper transferMapper;

    @Autowired
    private ApplicationProperties properties;

	public void moveData(String shortName) throws SQLException {
        // 创建变量保存表名
        String tableName = "";
        // 表名简称不为空时,通过表名简称前缀确定表名
        if (shortName == null || "".equals(shortName)) {
            // 表名简称为空直接结束
            System.out.println("表名不能为空");
            return;
        }
        // 根据简称前缀拼接出全表名
        if (shortName.contains("c")) {
            tableName = shortName.replace("c", "ctlm");
        } else if (shortName.contains("i")) {
            tableName = shortName.replace("i", "inv");
        } else if (shortName.contains("w")) {
            tableName = shortName.replace("w", "weight");
        }
        // 表名不为空时才可进行数据转移操作
        if (tableName == null || "".equals(tableName)) {
            // 表名为空说明表名简称前缀无法识别
            System.out.println("无法识别表");
            return;
        } else {
            move(tableName, shortName);
        }
        // 正常执行完成打印成功消息
        System.out.println(shortName + "数据转移完毕");
    }

    private void move(String tableName, String shortName) throws SQLException {
        // 建立发送者连接
        Connection conSend = DriverManager.getConnection(properties.getSendUrl(), properties.getSendName(), properties.getSendPassword());
        Statement stmtSend = conSend.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
        // 拿到查询sql
        String sql = properties.getSendSql();
        // 拼接——替换掉配置中的tableName和shortName
        sql = sql.replace("tableName", tableName);
        sql = sql.replace("shortName", shortName);
        try {
            // 通过拼接好的sql查询数据并保存到结果集
            ResultSet send = stmtSend.executeQuery(sql);
            if (send == null) {
                // 结果集为空说明没有新数据,不进行后续操作
                System.out.println("没有需要进行迁移的数据");
                return;
            }
            // 建立接收者连接
            Connection conAccept = DriverManager.getConnection(properties.getAcceptUrl(), properties.getAcceptName(), properties.getAcceptPassword());
            Statement stmtAccept = conAccept.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            // 定位接收表
            ResultSet accept = stmtAccept.executeQuery("select * from " + tableName);
            // 遍历发送者结果集
            while (send.next()) {
                // 开启新增
                accept.moveToInsertRow();
                // 获取当前表结构
                ResultSetMetaData metaData = send.getMetaData();
                // 通过表结构字段数遍历并设置当前行数据
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    accept.updateString(metaData.getColumnLabel(i), send.getString(i));
                }
                // 保存新增内容
                accept.insertRow();
                // 创建column保存需要修改的字段名
                String column = properties.getUpdateColumn();
                column = column.replace("shortName", shortName);
                // 修改发送者表需要的字段数据
                send.updateString(column, properties.getUpdateString());
                send.updateRow();
            }
            // 有异常时打印异常信息
        } catch (SQLException e) {
            System.out.println(e.getMessage());
        }
    }
}

End

功能拓展文章链接:java-数据迁移-定制拓展
定制拓展:
1.表数据迁移时,还需要将该表的某些字段数据抽取保存到另一张表中
我给它定义为——一对多数据迁移(手动滑稽)
2.(身份互换)接收者也需要将部分数据迁移到发送者,甚至需要关联查询到数据并保存到发送者,数据迁移后同样需要对某字段进行某种标记
这要求发送者的对应表字段比接收者多,需要特殊处理
这算不算是一种——多对一数据迁移(手动捂脸)

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值