該文使用源碼地址:地址html
因爲cnode上的一篇提問 node.js單線程,是否是就不用消息隊列了啊?
我當時的回答是
node
舉個例子,你要在數據表查是否有同名的,沒同名則插入。 由於node沒法按整個請求的sql塊做爲執行單元,而是按sql條做爲了執行單元,那麼按上面的來講兩個select會前後到達,而第一條insert並無插入,致使第二個select查詢爲空,還會繼續插入用戶。(若是表小可能不會出現,表大必現) 而消息隊列則至關因而已將請求的整個sql塊做爲執行單元,即完成了整個請求的select和insert,纔會執行下一個請求的select和insert。
這個回答是根據我以往在node遇到的坑,來回答的。貌似頗有道理,畢竟咱們平時執行node都是按條做爲異步的最小單元執行的。
可是過後我想,那爲何不能將node塊作爲順序執行單位呢?
git
沒錯,它確實能夠
遂在當天晚上作了一個簡單的塊運行庫,簡單測試了一下,感受好像是實現了,但因爲業務繁忙(產品需求激增),因此一直沒有時間去作優化和針對數據庫的實際的測試!遂於週末來測試一下。
我這邊實現了三套針對數據庫的併發測試
github
async function sqlCommon(sqlCommonName = 'sqlCommon') { let conn; try{ conn = await getConn(); let testSelete = await queryPromise( conn, 'SELECT * FROM `test` WHERE `name`= ? AND `version`=?', [getName(sqlCount),sqlCount] ); if(testSelete.length>0) { let testRes = await queryPromise( conn, 'UPDATE `test` SET `name`= ?,`version`=?+1 WHERE `version`=?', [getName(sqlCount+1),sqlCount,sqlCount] ); if(testRes.affectedRows>0) { sqlCount++; } else { console.log(`${sqlCommonName} failed:${sqlCount}`) } } else { console.log(`${sqlCommonName} failed:${sqlCount}`) } conn.release(); } catch(e){ console.log(`${sqlCommonName} failed:${sqlCount}`) conn.release(); // console.log(e.stack) } }
async function sqlTrans() { let conn; try{ conn = await getConn(); await queryPromise(conn,'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;') beginTransaction(conn); let testSelete = await queryPromise( conn, 'SELECT * FROM `test` WHERE `name`= ? AND `version`=?', [getName(sqlCount),sqlCount] ); if(testSelete.length>0) { let testRes = await queryPromise( conn, 'UPDATE `test` SET `name`= ?,`version`=?+1 WHERE `version`=?', [getName(sqlCount+1),sqlCount,sqlCount] ); if(testRes.affectedRows>0) { sqlCount++; } else { console.log(`sqlTrans failed:${sqlCount}`) rollback(conn); } } else { console.log(`sqlTrans failed:${sqlCount}`) } commit(conn); conn.release(); } catch(e){ console.log(`sqlTrans failed:${sqlCount}`) // console.log(e.stack);//這裏會爆出不少事務鎖錯誤 rollback(conn); conn.release(); } }
function sqlBlock() { return new Promise ((reslove,rejected)=>{ BlockRun.run('sqlBlockChannel1',async ()=>{ await sqlCommon('sqlBlock'); reslove(true) },3000); }); }
http.createServer( async (request, response) => { try { let pathname = url.parse(request.url).pathname; //console.log(`url:http://127.0.0.1:${port}{$pathname}`) let showText = 'test'; switch (pathname) { case '/clear': await sqlClear(); showText = 'clear'; break; case '/common': await sqlCommon(); showText = 'common'; break; case '/trans': await sqlTrans(); showText = 'trans'; break; case '/block': await sqlBlock(); showText = 'block'; break; } response.writeHead(200, {'Content-Type': 'text/html'}); response.write(showText); response.end(); } catch(e) { console.log(e.stack) } }).listen(port);
其餘代碼文件地址數據庫
到這裏有人會說了,你這個ab壓力過小了,固然沒什麼了,其實我想說,主要仍是數據和樂觀鎖結果太難看了,我要照顧一下。
你們想看塊執行的牛逼之處就讓你們看個痛快
npm
還有誰不服!簡直就是併發小神奇啊!若是是我的建站抗併發的話足夠了!無須事務照樣抗併發,性能槓槓的!
對結果有疑問的同窗能夠自行測試,注意兩點:併發