nodejs定时轮询数据库“排队消费”

目录可直接阅读核心部分, 其他内容为辅助

五、 核心部分

零、脚本中方法调用流水线概括

一、 方法解释:脚本中依赖包引入与脚本运行入口

二、 方法解释:远程接口调用

三、 方法解释:抽象sql公共部分

四、 方法解释:格式化打印日志logformat

六、 方法解释:脚本中使用的nodejs依赖

七、 总结


零、脚本中方法调用流水线概括

  • ★处标明序号

    1. start(); # 入口启动
    function start() {
    	setInterval(()=>{3. init(); # 获取待消费数据方法
    	}, 4000);2. impl(); # 第二个setInterval定时调用方法
    }
    
    async function init() {
    	if(libproc) {
    		return;
    	}
    	sharesql =4.getsharesql(); # 获取公共sql的方法(有多处使用了相同的sql字段)
    	logformat('重复执行start')
    	libproc = true;5.sumtody(); # 获取分页总数
    }
    
    async  function sumtody() {
       let sumsql = `SELECT  ...nt(*) as sum ${sharesql}`;
       mysql_pool.query(sumsql, function(err, rows, fields){
            sum = rows.shift().sum;
       	logformat(getNowDateTime()+'. sum:',sum);6.handlepage(sum); # 具体分页处理内容(其中包括了分页期间轮询等待)
       });
    }
    
    async function handlepage(sum) {
    	let totalPage = Math.floor(sum/pageSize);
    	let remain = sum % pageSize;
    	if(remain > 0) {
    		totalPage += 1;
    	}
    	for(let i=1; i<=totalPage; i++) {
                    let sql = `SELECT  b.stu_se... limit ?, ?`;
     	        let startcount = (i-1)*pageSize;
    		...
    		mysql_pool.query(sql, [(i-1)*pageSize, pageSize], function(err, rows, fields){
    			if(err) {
    				logformat(err);
    			}7.pagequeue = rows; # 塞入数组等待另一个setInterval消费
    		});
    		await sleep(1000);// 等待mysql异步查询结果
    		while(pagequeue.length == 0) {
    		   await sleep(1000);
    		}
    		while(pagequeue.length > 0) {
    		   await sleep(1000);
    		}
    	}8.libproc = false; # 修改标识, 第二个setInterval方法中对标识做判断
    
    }
    
    function impl() {
    	setInterval(()=>{9.if(pagequeue.length > 0) { # 这里是第二个setInterval方法, 如果数组队列中有值则进行消费
    				★9.1 let item = pagequeue.shift(); # 取出数组中的元素
    				logformat('patient_id:', item.patient_id, 'reg_id:', item.reg_id, 'orgCode:', ...lm_orgCode);
    				var jsonobj = {
    					regId: item.reg_id,
    					orgCode: ...lm_orgCode
    					};
    				var ...gCount  = 0;
    				var ...gFilePath  = "";
    				var sqlstr = `selec... `
    					...s.query(sqlstr, [item.reg_id], (err, result) => {
    						...10. handleSyncFlag(jsonobj, ...ImgCount); # 处理业务逻辑
    					});
    		}
    	},2000);
    
    }
    function handleSyncFlag(jsonobj, ...unt) {
       request.post(`${zycloud...ceAddress}/get...Count`).send(jsonobj).end(function (err, resp) {
    	... 
    	let ...Count = resp.body.data;
    	logformat('...像数量:',...gCount,'本地图片数量:',...Count);   
    	if(...mgCount != ...gCount) {11.updat...yncFlag(jsonobj); # 处理业务逻辑           	
    	} 
    
      }); 
    }
    
    
一、脚本中依赖包引入与脚本运行入口
  • 介绍使用setInterval+标识判断模拟队列消费(此处获取的队列值为现查询数据库获取需要处理的业务数据)
  • 引入moment依赖。进行时间格式化操作sql拼接
  • 引入superagent依赖。进行远程接口调用接口调用
    var moment = require('moment');
    var request = require('superagent')
    
    // 启动入口
    start();
    function start() {
    	setInterval(()=>{
    		init();
    	}, 4000);
    	impl();
    }
    async function init() {
    	if(libproc) {
    		return;
    	}
    	sharesql = getsharesql();
    	logformat('重复执行start')
    	libproc = true;
    	sumtody();
    }
    ...
    
二、 远程接口调用。
  • 接口调用, 处理返回值

    function handleSyncFlag(jsonobj, p...ImgCount) {
       request.post(`${z...fil...ress}/ge...ount`).send(jsonobj).end(function (err, resp) {
    	if(err) {
    		logformat('getrea...ount.err:', err);
    		return;
    	}   
    	logformat('接口返回:'+JSON.stringify(resp.body));
    	if (resp.body.success == false) {
    		logformat('success.faluse:', JSON.stringify(resp.body)); 
    		return;
    	}   
    	let ...ImgCount = resp.body.data;
    	logformat('...数量:',...imgCount,'本地图片数量:',p...ImgCount);   
    	if(...ImgCount != p...ImgCount) {
    		updateP...SyncFlag(jsonobj);	            	
    	} 
    
      }); 
    }
    
三、抽象sql公共部分getsharesql,
  • 避免sql查询语句冗余, 并进行测试test()

    function getsharesql() {
    // var time = '2023-12-20';
     var time = moment().format('YYYY-MM-DD');
     logformat('time:', time);
     let sharesql = ` FROM registra...tu_time BETWEEN CONCAT('${time}',' 00:00:00') AND CONCAT('${time}',' 23:59:59') and st...m != '' `;
     return sharesql;
    }
    function test() {
    	setInterval(()=>{
    		var a = `'${getsharesql()}'`; 
    		var b = a + `limit ?`;
    		logformat(b);
    	}, 1000);
    }
    
四、格式化打印日志logformat
  • 获取格式化时间戳moment().format('YYYY-MM-DD HH:mm:ss')
  • 使用语法拼接sql
    `update reg...ud=2,sync_time='${moment().format('YYYY-MM-DD HH:mm:ss')}' where reg_id=${jsonobj.regId}`;
    
    function update...cFlag(jsonobj) {
        var sqlArr = new Array();
        sqlArr.push(`update reg...ud=2,sync_time='${moment().format('YYYY-MM-DD HH:mm:ss')}' where reg_id=${jsonobj.regId};`);
        var sql = sqlArr.join('');
        mysql_pool.query(sql, function (err, rows, fields) {
    	if (err) {
    	    logformat('更新...nc_cloud=2 报错. err' + err);
    	    return;
    	}
    	logformat('更新... 成功. reg_id:' + jsonobj.regId);
        })
    }
    function logformat(... msgstr) {
        var msgobj = {
            "orgCode": z...film_orgCode,
            "orgName": z...film_orgName,
            "msg": msgstr,
            "time": moment().format('YYYY-MM-DD HH:mm:ss')
        }
        console.log("msgstr:", msgstr);
    }
    
五. 核心部分。
  • 轮询等待消费完成, 再继续进行下一次循环。
  • libproc 进行标识更新进行handlepage方法的被重新调用
    async function handlepage(sum) {
    	let totalPage = Math.floor(sum/pageSize);
    	let remain = sum % pageSize;
    	if(remain > 0) {
    		totalPage += 1;
    	}
    	for(let i=1; i<=totalPage; i++) {
                    let sql = `SELECT  b.stu_se....stu_time ${sharesql}  order by a.reg_id asc limit ?, ?`;
     	        let startcount = (i-1)*pageSize;
    		logformat('startcount:',startcount,'pagesize:',pageSize)
    		mysql_pool.query(sql, [(i-1)*pageSize, pageSize], function(err, rows, fields){
    			if(err) {
    				logformat(err);
    			}
    			pagequeue = rows;
    		});
    		await sleep(1000);// 等待mysql异步查询结果
    		while(pagequeue.length == 0) {
    		   await sleep(1000);
    		}
    		while(pagequeue.length > 0) {
    		   await sleep(1000);
    		}
    	}
    	libproc = false;
    
    }
    
  • 等待第二个setInterval消费完成pagequeue中的数据
    function impl() {
    	setInterval(()=>{
    	    if(pagequeue.length > 0) { # 这里是第二个setInterval方法, 如果数组队列中有值则进行消费
    				let item = pagequeue.shift(); # 取出数组中的元素
    				logformat('patient_id:', item.patient_id, 'reg_id:', item.reg_id, 'orgCode:', ...lm_orgCode);
    				var jsonobj = {
    					regId: item.reg_id,
    					orgCode: ...lm_orgCode
    					};
    				var ...gCount  = 0;
    				var ...gFilePath  = "";
    				var sqlstr = `selec... `
    					...s.query(sqlstr, [item.reg_id], (err, result) => {
    						...
    						handleSyncFlag(jsonobj, ...ImgCount); # 处理业务逻辑
    					});
    		}
    	},2000);
    
    }
    
六、脚本中使用的nodejs依赖 package.json
```js
{
  "name": "z...-client",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "...",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "child_process": "^1.0.2",
    "cors": "^2.8.5",
    "dicom-parser": "^1.8.21",
    "express": "^4.17.1",
    "fs": "0.0.1-security",
    "http": "0.0.1-security",
    "iconv-lite": "^0.6.3",
    "ioredis": "^5.3.2",
    "md5": "^2.3.0",
    "moment": "^2.29.1",
    "mssql": "^6.0.1",
    "mysql": "^2.18.1",
    "node-schedule": "^2.0.0",
    "path": "^0.12.7",
    "pg": "^8.6.0",
    "redis": "^3.1.2",
    "socket.io-client": "^2.2.0",
    "superagent": "^6.1.0",
    "uuid": "^9.0.0"
  }
}

```

七、总结

脚本中使用 ... 处理了敏感信息

  1. 两次调用setInterval方法进行队列消费
  2. for循环中使用while等待
  3. 使用标识判断setInterval中的业务处理顺序
  4. 使用了moment、superagen、依赖处理时间字符串格式与远程接口调用,使用nodejs语法灵活拼接字符串。
  5. 使用数组作为消费队列,并使用shift数组方法获取最先进入队列的元素(第一个元素)
  6. 第一次使用的setInterval时长 大于 第二次的setInterval。第一次为4000ms, 第二次2000ms。这样做是因为可以加快队列的消费速度。
  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Node.js中操作MySQL数据库,你需要引入对应的数据库操作模块,并进行必要的配置。以下是一个示例代码: ```javascript const mysql = require('mysql'); const connection = mysql.createConnection({ host: 'localhost', // 数据库地址 user: 'root', // 用户名 password: '', // 密码 database: 'class', // 数据库名 multipleStatements: true, // 允许执行多条语句 }); // 建立与数据库的连接 connection.connect((err) => { if (err) throw err; console.log('连接成功'); }); // 执行查询操作 const sql = 'SELECT * FROM user'; connection.query(sql, (err, result) => { if (err) { console.log(err.message); } else { console.log('------------------'); console.log(result); console.log('查询完成'); console.log('------------------'); } }); // 关闭数据库连接 connection.end((err) => { if (err) throw err; console.log('关闭成功'); }); ``` 以上代码示例中,我们首先引入了mysql模块,并创建了一个与数据库的连接。然后,我们执行了一条查询语句,查询了user表中的全部内容,并将结果打印出来。最后,我们关闭了与数据库的连接。请注意,你需要根据你的实际情况修改连接配置和查询语句。 #### 引用[.reference_title] - *1* [nodeJs操作mysql数据库](https://blog.csdn.net/qq_40375518/article/details/107521107)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [nodejs操作MySQL数据库](https://blog.csdn.net/weixin_52851967/article/details/128589773)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Node.js——在Node.js中操作MySQL](https://blog.csdn.net/weixin_50233139/article/details/121470144)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡斌附体

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值