数据库迁移脚本

数据库迁移脚本

这次使用node.js作为工具去做

至于为啥用node.js??

可能是js在异步操作上非常高效? (但它仍然是单线程的,对于 CPU 密集型的操作可能不如其他语言。)

本质就是先查再插

例子:

{"name": "数据库迁移","version": "1.0.0","dependencies": {"log4js": "^6.9.1","mysql2": "^3.5.2"}
}
// 引入依赖
const mysql = require('mysql2/promise');
const log4js = require('log4js');// 配置日志,此处格式需要自定义
log4js.configure({appenders: {errorLog: { type: 'file', filename: 'error.log' }},categories: {default: { appenders: ['errorLog'], level: 'error' }}
})
const logger = log4js.getLogger();// 数据迁移配置
const migrationConfig = {batchSize: 1000, // 每批处理的数据量sourceDB: {host: 'db2.ilaw.com.cn',port: '3306',user: 'developer',password: 'cpsoft_873406',database: 'kinglex',connectionLimit: 10,  // 设置连接数限制queueLimit: 100,  // 设置队列限制acquireTimeout: 30000,  // 设置获取连接的超时时间为30秒waitForConnections: true,  // 等待连接可用acquireRetryCount: 3,  // 获取连接的重试次数acquireRetryWait: 1000,  // 获取连接的重试间隔时间为1秒supportBigNumbers: true,bigNumberStrings: true},targetDB: {host: 'db2.ilaw.com.cn',port: '3306',user: 'developer',password: 'cpsoft_873406',database: 'kinglex',connectionLimit: 20,  // 设置连接数限制queueLimit: 200,  // 设置队列限制acquireTimeout: 5000,  // 设置获取连接的超时时间为5秒waitForConnections: true,  // 等待连接可用acquireRetryCount: 5,  // 获取连接的重试次数acquireRetryWait: 500,  // 获取连接的重试间隔时间为0.5秒supportBigNumbers: true,bigNumberStrings: true}
};// 创建源数据库连接池
const sourcePool = mysql.createPool(migrationConfig.sourceDB);// 创建目标数据库连接池
const targetPool = mysql.createPool(migrationConfig.targetDB);async function cust_linkman() {let sourceConnection, targetConnection;try {sourceConnection = await getConnectionFromSourcePool();targetConnection = await getConnectionFromTargetPool();let offset = 0;while (true) {const [rows] = await sourceConnection.query(`SELECT * FROM cust_linkman LIMIT ${offset}, ${migrationConfig.batchSize}`);console.log(rows)if (rows.length === 0) {// 没有更多数据,数据迁移完成break;}const dataBase = []const dataPerson = []// 处理当前批次的数据for (const row of rows) {const typeO = row.type;let EntityType = null;if(typeO!=null && typeO==1){EntityType=501;}if(typeO!=null && typeO==2){EntityType=503;}if(typeO!=null && typeO==3){EntityType=506;}if(typeO!=null && typeO==4){EntityType=505;}if(typeO!=null && typeO==5){EntityType=504;}if(typeO!=null && typeO==6){EntityType=507;}const transformedUserBase = {id: row.id,groupId: null,type: 5, //5就是联系人name: row.name,nameIndex: row.firstName,nameGBK: null,simpleName: null,formerName:row.beforeName,codeType:row.cardType,code:row.IDCard,mobile1:row.mobile1,mobile2:row.mobile2,phone:null,country:row.country,province:row.province,city:row.city,district:row.district,businessArea:row.businessArea,countryCode:null,provinceCode:null,cityCode:null,districtCode:null,businessAreaCode:null,address:null,description: row.description,remark: row.memo,teamId: row.teamId,managerId: row.managerId,shareId:null,resource: row.isAuto,importanceEvaluate:null,caseSourceEmpId:null,creditedLevel:null,relationLevel:null,isImportance:null,importanceDesc:null,isinstancy:null,instancyDesc:null,status1 :null,email: row.email,renameStatus :null,isGetGSData :null,isGetGSGJData :null,relation :null,deptId :null,dept :null,relationCustomer :null,company:row.company,createUserId:row.createUserId,createTime:row.createDate,modifyTime:row.updateDate,isDel:row.isDel,belongTo:row.custId,mobile3:row.mobile3,entityType:EntityType}const transformedUserPerson = {custId: row.id,groupId: null,type: 3,  //3就是联系人sex : row.sex,marriage: row.marriage,homePhone:row.homePhone,qq: row.qq,nation:row.nation,birthday: row.birthday,registeredAddress: row.address,bigDiploma: row.bigDiploma,origin: row.origin,face: row.face,religion: row.religion,workCompany: row.workCompany,workDept: row.workDept,workDimission:row.workDimission,workJob:row.workJob,workRight: row.workRight,workPhone:row.workPhone,workFax: row.workFax,workAddress: row.workAddress,cardDept: null,cardAddress: null,cardAddressZip: null,endUniversity: row.endUniversity,workZip: row.workZip,workWebsite: row.workWebsite,workLinePhone: row.workLinePhone,msn: row.msn,homeAddress: row.homeAddress,homeZip: row.homeZip,communicationAddress: row.communicationAddress,communicationZip: row.communicationZip,like: row.lkmLike,specialty: row.specialty,consortInfo: row.consortInfo,childInfo: row.childInfo,otherInfo: row.otherInfo,company:row.company,createUserId:row.createUserId,createTime: row.createDate,modifyTime:row.updateDate,isDel : row.isDel}dataBase.push(transformedUserBase)dataPerson.push(transformedUserPerson)}const valueb = dataBase.map(Object.values)console.log("valueb----------------------------")console.log(valueb)const valuep = dataPerson.map(Object.values)try {await targetConnection.query('INSERT IGNORE INTO `cust_base_info`'  + 'VALUES ?',[valueb]);await targetConnection.query('INSERT IGNORE INTO `cust_person`'  +'VALUES ?',[valuep]);} catch (err) {// 处理迁移过程中的错误// 可以选择继续处理下一条数据或者中断迁移logger.error(err);console.error('出错: ', err);}//console.log('cst_opponent_organization_company 迁移成功:' + data.map(item => item.id + ''))console.log('cst_opponent_organization_company 迁移成功:' + valueb.length + '条')offset += migrationConfig.batchSize;}console.log('cst_opponent_organization_company 迁移完成')} catch (err) {console.error('出错: ', err);throw err;} finally {// 释放连接回连接池if (sourceConnection) {sourceConnection.release();}if (targetConnection) {targetConnection.release();}}
}async function cst_opponent_organization_company() {let sourceConnection, targetConnection;try {sourceConnection = await getConnectionFromSourcePool();targetConnection = await getConnectionFromTargetPool();let offset = 0;while (true) {const [rows] = await sourceConnection.query(`SELECT *, cst_opponent.id as id, cst_opponent.address as address, cst_opponent.company as company, cst_opponent.createTime as createTime,cst_opponent.createUserId as createUserId, cst_opponent.modifyTime as modifyTime,cst_opponent.isDel as isDelFROM cst_opponentleft join (select * from cst_opponent_organization where isDel = 0) opponent_organization  on opponent_organization.opponentId = cst_opponent.idwhere type = 1 LIMIT ${offset}, ${migrationConfig.batchSize}`);if (rows.length === 0) {// 没有更多数据,数据迁移完成break;}const data = []// 处理当前批次的数据for (const row of rows) {// 在这里执行具体的数据转换、处理和插入操作// 转换和映射数据const transformedUser = {custId: row.id,groupId: null,type: 2,scope: row.scope,property: row.property,fax: row.fax,website: row.website,officeArea: row.officeArea,turnover: row.turnover,employeeNumber: row.employeeNumber,creditCode: row.creditCode,bankroll: row.bankroll,code: row.code,establishDate: row.finishDate,chieftain: row.chieftain,businessScope: null,taxNo: row.taxNo,bizPhone: row.bizPhone,bizAddress: row.bizAddress,bank1: row.bankOne,bankAccountName1: row.bankAccountNameOne,bankAccountId1: row.bankAccountIdOne,bank2: row.bankTwo,bankAccountName2: row.bankAccountNameTwo,bankAccountId2: row.bankAccountIdTwo,bank3: row.bankThree,bankAccountName3: row.bankAccountNameThree,bankAccountId3: row.bankAccountIdThree,zip: row.zip,brand: row.brand,bizLicense: row.bizLicense,propertySubName: null,billCode: null,company :row.company,createUserId :row.createUserId,createTime :row.createTime,modifyTime :row.modifyTime,isDel :row.isDel};data.push(transformedUser)}const value = data.map(Object.values)try {await targetConnection.query('INSERT IGNORE INTO cust_company ' +'(custId, groupId, type, scope, property, ' +'fax, website, officeArea, turnover, employeeNumber, ' +'creditCode, bankroll, code, establishDate, chieftain, ' +'businessScope, taxNo, bizPhone, bizAddress, bank1, bankAccountName1, ' +'bankAccountId1, bank2, bankAccountName2, bankAccountId2, bank3, ' +'bankAccountName3, bankAccountId3, zip, brand, bizLicense, ' +'propertySubName, billCode, company ,createUserId ,createTime ,modifyTime ,isDel) ' +'VALUES ?',[value]);} catch (err) {// 处理迁移过程中的错误// 可以选择继续处理下一条数据或者中断迁移logger.error(err);console.error('出错: ', err);}//console.log('cst_opponent_organization_company 迁移成功:' + data.map(item => item.id + ''))console.log('cst_opponent_organization_company 迁移成功:' + data.length + '条')offset += migrationConfig.batchSize;}console.log('cst_opponent_organization_company 迁移完成')} catch (err) {console.error('出错: ', err);throw err;} finally {// 释放连接回连接池if (sourceConnection) {sourceConnection.release();}if (targetConnection) {targetConnection.release();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/156479.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Blender中的集合(collection)概念

集合是一种逻辑上的分组方式,它可以让你把一些相似或相关的对象放在一起,而不影响它们的变换关系(不像父子关系那样)。集合可以用来简化你的场景,或者方便你在不同的文件或场景之间进行追加或链接。 集合有以下的特点…

c 文本终端直接写framebuffer 显示直线

根据这思路&#xff0c;操作framebuffer 显示图片和视频 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <string.h> #include <…

Android codec2 视频框架之输出端的内存管理

文章目录 前言setSurfacestart从哪个pool中申请buffer解码后框架的处理流程renderOutbuffer 输出显示 前言 输出buffer整体的管理流程主要可以分为三个部分&#xff1a; MediaCodc 和 应用之间的交互 包括设置Surface、解码输出回调到MediaCodec。将输出buffer render或者rele…

手机照片一键去水印轻松摆脱不需要的旁观者

是什么让照片中的意外客人成为挑战&#xff1f;我们都经历过这种情况——在热门地标或繁忙的城市街道拍照&#xff0c;不可避免地会在画面中捕捉到陌生人。有时他们会无意中抢尽风头&#xff0c;转移观众的注意力。 这些水印不仅影响了照片的美观度&#xff0c;还给我们的观赏体…

京东数据分析软件(京东平台数据分析):2023年Q3扫地机器人行业消费报告

随着90后、00后逐渐成为消费主力军&#xff0c;他们对生活品质更加关注、健康意识进一步增强&#xff0c;再加上“懒人经济”的盛行&#xff0c;人们对扫地机器人的使用率和关注热情也不断增长。 根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;今年7月份-9月份&#xf…

AI大爆发的时代,未来的年轻人怎样获得机会和竞争力?

文章目录 引言AI与教育工作者教育资源不平衡 这次&#xff0c;狼真的来了。 引言 AI正迅猛地改变着我们的生活。 根据高盛发布的一份报告&#xff0c;AI有可能取代3亿个全职工作岗位&#xff0c;影响全球18%的工作岗位。在欧美&#xff0c;或许四分之一的工作可以用AI完成。另…

第四代智能井盖传感器,更迭智能井盖监测办法

人工检查井盖是一项耗时且效率低下的工作&#xff0c;需要工作人员逐个进行检查。由于这种方式无法实时监测井盖的状态&#xff0c;当井盖出现故障时无法及时将信息反馈给相关人员&#xff0c;从而影响了井盖的维修效率。此外人工检查还受到天气、光线等环境因素的影响较大&…

OpenGL 绘制文本(QPainter)

文章目录 一、简介二、实现代码三、实现效果一、简介 OpenGL中并没有绘制文本的相关函数,因此这里仍然用的是Qt中的QPainter工具来绘制文本,但是其相关的定位这里仍然会用OpenGL中的坐标转换。这里对其也进行封装一下,方便后续使用。 二、实现代码 TextDrawable.h #ifndef T…

强化学习是一种什么样的方法,通常可以用来解决什么特点的问题

强化学习&#xff08;Reinforcement Learning&#xff0c;简称RL&#xff09;是机器学习的一个分支&#xff0c;其主要关注如何使智能体&#xff08;Agent&#xff09;通过与环境的交互学习&#xff0c;以在面临不同情境时做出最优决策。在强化学习中&#xff0c;智能体通过试错…

java获取shp文件坐标系

1&#xff0c;pom依赖 <dependency><groupId>org.geotools</groupId><artifactId>gt-referencing</artifactId><version>24.0</version> </dependency>2&#xff0c;单元测试 import org.geotools.data.shapefile.Shapefile…

卷积神经网络(ResNet-50)鸟类识别

文章目录 卷积神经网络&#xff08;CNN&#xff09;mnist手写数字分类识别的实现卷积神经网络&#xff08;CNN&#xff09;多种图片分类的实现卷积神经网络&#xff08;CNN&#xff09;衣服图像分类的实现卷积神经网络&#xff08;CNN&#xff09;鲜花的识别卷积神经网络&#…

基于社交网络算法优化概率神经网络PNN的分类预测 - 附代码

基于社交网络算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于社交网络算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于社交网络优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

一、MySQL-Replication(主从复制)

1.1、MySQL Replication 主从复制&#xff08;也称 AB 复制&#xff09;允许将来自一个MySQL数据库服务器&#xff08;主服务器&#xff09;的数据复制到一个或多个MySQL数据库服务器&#xff08;从服务器&#xff09;。 根据配置&#xff0c;您可以复制数据库中的所有数据库&a…

Flowable工作流基础篇

文章目录 一、Flowable介绍二、Flowable基础1.创建ProcessEngine2.部署流程定义3.启动流程实例4.查看任务5.完成任务6.流程的删除7.查看历史信息 三、Flowable流程设计器1.Eclipse Designer1.1 下载安装Eclipse1.2 安装Flowable插件1.3 创建项目1.4 创建流程图1.5 部署流程 2.F…

4、基础入门——30余种加密编码进制web数据库系统代理

密码存储加密 MD5值是32位或16位由数字“0-9”和字母"a-f"所组成的字符串&#xff1b;SHA1这种加密的密文特征跟MD5差不多&#xff0c;只不过位数是40位&#xff1b;NTLM是Windows的哈希密码&#xff0c;标准通讯安全协议&#xff1b;AES、DES、RC4是非对称性加密算…

Maven工程继承关系,多个模块要使用同一个框架,它们应该是同一个版本,项目中使用的框架版本需要统一管理。

1、父工程pom.xml <?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/PO…

KMP——字符串匹配

朴素匹配的逻辑&#xff1a; 将原串的指针移动至本次发起点的下一个位置&#xff08;b字符处&#xff09;&#xff1b;匹配串的指针移动至起始位置。尝试匹配&#xff0c;发现对不上&#xff0c;原串的指针会一直往后移动&#xff0c;直到能够与匹配串对上位置。 如图&#x…

(02)vite环境变量配置

文章目录 将开发环境和生产环境区分开环境变量vite处理环境变量loadEnv 业务代码需要使用环境变量.env.env.development.env.test修改VITE_前缀 将开发环境和生产环境区分开 分别创建三个vite 的配置文件&#xff0c;并将它们引入vite.config.js vite.base.config.js import…

深入探讨软件测试技术:方法、工具与最佳实践

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 引言 软件测试是软件开发生命周期中至关重要的…

SO3 与so3 SE3与se3 SIM3

文章目录 1 旋转*叉乘1.1 旋转矩阵的导数1.2 物理意义1.3 实例1.4 角轴与反对称矩阵 2 SO3 与so32.1 so3 2 SO32.2 SO3 2 so3 3 SE3 与se33.1 se3 2 SE3:3.2 SE3 2 se3 4 SIM3 与sim35 Adjoint Map 1 旋转*叉乘 1.1 旋转矩阵的导数 根据旋转矩阵的性质&#xff1a; R R T I …