国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Express.js】數(shù)據(jù)庫(kù)初始化

這篇具有很好參考價(jià)值的文章主要介紹了【Express.js】數(shù)據(jù)庫(kù)初始化。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

數(shù)據(jù)庫(kù)初始化

????????在軟件開(kāi)發(fā)階段和測(cè)試階段,為了方便調(diào)試,我們通常會(huì)進(jìn)行一系列的數(shù)據(jù)庫(kù)初始化操作,比如重置數(shù)據(jù)表,插入記錄等等,或者在部署階段進(jìn)行數(shù)據(jù)初始化的操作

????????根據(jù)前面章節(jié)介紹過(guò)的 knex.jssequelize.js,我們可以利用它們提供的方法進(jìn)行DDL,本節(jié)就數(shù)據(jù)庫(kù)表重置的初始化行為做一點(diǎn)探討,表結(jié)果為User{id: num, name: string, age: num},數(shù)據(jù)庫(kù)采用sqlite

Knex DDL

以下是利用 knex.schema 的一個(gè)簡(jiǎn)單示例:
knex.js

const knex = require('knex');
const fs = require('fs');

const sqlClient = knex({
    client: 'sqlite3',
    connection: {
        filename: `${__root}/db/data.db`,
        acquireConnectionTimeout: 1000
    },
    useNullAsDefault: true
});

module.exports = sqlClient;

init.js

global.__root = __dirname;

const knex = require('./knex.js');

const drop = knex.schema.dropTableIfExists('user');
const create = knex.schema.createTable('user', (user)=>{
    user.increments('id').notNullable().primary();
    user.text('name').notNullable();
    user.integer('age').notNullable()
});
const promises = [drop,create];
Promise.all(promises)
.then(res=>{
    console.log('Database inits successfully!')
}).catch(err=>{
    console.error(err);
})

Sequelize DDL

以下是利用 Sequelize.Model 的一個(gè)簡(jiǎn)單示例:
sequelize.js

const { Sequelize,DataTypes,Model } = require('sequelize');
const fs = require('fs');

const sqlClient = new Sequelize({
    dialect: 'sqlite',
    storage: `${__root}/db/data.db`
})

const User = sqlClient.define('User', {
    id: {
        primaryKey: true,
        type: DataTypes.INTEGER,
        allowNull: false,
        autoIncrement: true
    },
    name: {
        type: DataTypes.STRING,
        allowNull: false
    },
    age: {
        type: DataTypes.INTEGER,
        allowNull: false
    }
}, {
    tableName: 'user',
    timestamps: false,
});

module.exports = {
    sqlz: sqlClient,
    User
}

init.js

global.__root = __dirname;

const { User } = require('./sequelize');

// User.drop();User.sync();
User.sync({ force: true })  //這個(gè)相當(dāng)于前兩個(gè)的結(jié)合體
    .then(res=>{
        console.log('Database inits successfully!');
    }).catch(err=>{
    console.error(err);
})

SQL文件

????????Springboot作為Web后端最流行的框架之一,想必各位都接觸過(guò)或者聽(tīng)說(shuō)過(guò),在Springboot中,可以在配置文件中設(shè)置sql腳本的路徑,在項(xiàng)目啟動(dòng)時(shí)執(zhí)行sql腳本來(lái)完成初始化。
????????這是一種非常好的方法,因?yàn)橛袝r(shí)候我們項(xiàng)目場(chǎng)景下的數(shù)據(jù)庫(kù)表結(jié)構(gòu)與關(guān)系可能非常復(fù)雜,而且不同語(yǔ)言,不同框架的實(shí)現(xiàn)有些區(qū)別,用代碼去完成初始化操作將是一件非常麻煩的事,既然SQL是關(guān)系型數(shù)據(jù)庫(kù)通用的語(yǔ)言,那我們就可以通過(guò)SQL腳本來(lái)定義數(shù)據(jù)庫(kù)表的結(jié)構(gòu)和關(guān)系,可以手寫(xiě)SQL腳本,也可以借助如Navicat之類的工具設(shè)計(jì)表然后轉(zhuǎn)儲(chǔ)sql腳本,然后交給我們的程序去執(zhí)行,或者手動(dòng)執(zhí)行。

Node的sql框架千千萬(wàn),我在幾個(gè)主流框架中似乎都沒(méi)看到有提供執(zhí)行sql文件的特性,其實(shí)沒(méi)那么復(fù)雜,不從構(gòu)造完美的框架角度,僅以為項(xiàng)目服務(wù)的角度考慮來(lái)說(shuō)是這樣的,接下來(lái)我們就來(lái)簡(jiǎn)單實(shí)現(xiàn)一下通過(guò)sql腳本去初始化數(shù)據(jù)庫(kù)。

有兩條路:

  1. 運(yùn)行環(huán)境先安裝sqlite3客戶端,node讀取sql腳本內(nèi)容,node通過(guò)exec去指定目錄下,打開(kāi)sqlite3命令行連接sqlite數(shù)據(jù)庫(kù),同時(shí)把sql內(nèi)容傳遞過(guò)去,在sqlite3中執(zhí)行sql腳本完成數(shù)據(jù)庫(kù)初始化操作
  2. Node安裝sqlite3依賴,通過(guò)sql框架連接sqlite數(shù)據(jù)庫(kù),node讀取sql腳本內(nèi)容,對(duì)內(nèi)容進(jìn)行規(guī)范化處理只剩下純凈的sql語(yǔ)句后,交給sql框架以sql語(yǔ)句的形式去運(yùn)行

Springboot采用的就是第2種方法,那我們也在Node中實(shí)現(xiàn)一下吧
實(shí)現(xiàn)準(zhǔn)備好sql腳本 schemal.sql

-- 先刪除user表
DROP TABLE IF EXISTS `user`;
-- 定義表結(jié)構(gòu),并創(chuàng)建user表
CREATE TABLE `user` (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,  --自增主鍵
    name TEXT NOT NULL,
    age INTEGER NOT NULL
);

Knex

先用Knex作為sql框架做個(gè)示范。獲取到項(xiàng)目根目錄路徑后,建立數(shù)據(jù)庫(kù)連接:
knex.js

const knex = require('knex');
const fs = require('fs');

const sqlClient = knex({
    client: 'sqlite3',
    connection: {
        filename: `${__root}/db/data.db`,
        acquireConnectionTimeout: 1000
    },
    useNullAsDefault: true
});

module.exports = sqlClient;

接下來(lái),為客戶端實(shí)現(xiàn)執(zhí)行sql文件的方法:

  1. 定義runSql方法的傳參和返回
    我這里傳入sql文件的路徑,返回sql語(yǔ)句執(zhí)行的promise鏈
  2. 內(nèi)部實(shí)現(xiàn),首先通過(guò)fs模塊讀取sql腳本內(nèi)容并轉(zhuǎn)為字符串
  3. 把內(nèi)容中的注釋去掉
  4. 去掉內(nèi)容首尾的空格
  5. 去掉\r
  6. 去掉\n(我為了打印sql語(yǔ)段時(shí)更加美觀,省去了這一步,不影響執(zhí)行結(jié)果)
  7. 把內(nèi)容按照;號(hào)分割成一個(gè)個(gè)獨(dú)立的sql語(yǔ)句字串
  8. 過(guò)濾掉空字串(由每2個(gè)sql語(yǔ)句間的空格形成)
sqlClient.runSql = (path)=>{
    const script = fs.readFileSync(path).toString();
    console.log("Going to run a sql file:");
    console.log(script);
    /**
     * 拆成一句句sql來(lái)執(zhí)行是因?yàn)椋琸nex執(zhí)行一串語(yǔ)句時(shí),會(huì)把它們都算進(jìn)一個(gè)事務(wù)內(nèi)
     * 利用正則忽略注釋
     * 去首尾空格
     * 按冒號(hào)分句
     * 校驗(yàn)字串是否為sql語(yǔ)句
     * @type {string[]}
     */
    const sqls = script.replace(/\/\*[\s\S]*?\*\/|(--|\#)[^\r\n]*/gm, '').trim().replaceAll('\r','').split(';').filter(str=>{
        return str.trim() ? true : false;
    });
    console.log("sqls");
    console.log(sqls);
    console.log("start run:");
    const promises = sqls.map(sql=>{
        sql += ';';  // knex會(huì)自動(dòng)補(bǔ)上冒號(hào),加不加無(wú)所謂其實(shí)
        console.log("Going to run a sql:");
        console.log(sql);
        return sqlClient.raw(sql);
    })
    return promises;
}

到這里,我們就得到了純凈的一條條sql語(yǔ)句,接下來(lái)把sql語(yǔ)句丟給knex即可:
init.js

global.__root = __dirname;

const knex = require('./knex.js')

const promises = knex.runSql(`${__root}/db/schema.sql`);
Promise.all(promises)
    .then(res=>{
        console.log("Database inits successfully!")
    }).catch(err=>{
    console.error(err);
})

輸出結(jié)果:

D:\Workstation\gitee-localRepo\express-demo\DatabaseInit>node index.js
Going to run a sql file:
-- 先刪除user表
DROP TABLE IF EXISTS `user`;
-- 定義表結(jié)構(gòu),并創(chuàng)建user表
CREATE TABLE `user` (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,  --自增主鍵
    name TEXT NOT NULL,
    age INTEGER NOT NULL
);

sqls
[
  'DROP TABLE IF EXISTS `user`',
  '\n' +
    '\n' +
    'CREATE TABLE `user` (\n' +
    '    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,  \n' +
    '    name TEXT NOT NULL,\n' +
    '    age INTEGER NOT NULL\n' +
    ')'
]
start run:
Going to run a sql:
DROP TABLE IF EXISTS `user`;
Going to run a sql:


CREATE TABLE `user` (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age INTEGER NOT NULL
);
Server is ready on http://:::8080
Database inits successfully!

很好,我們可以很清晰的看到sql的執(zhí)行過(guò)程

Sequelize

????????如果你把knex這套照搬過(guò)去,把knex.raw換成sequelize.query,你也許會(huì)尷尬的發(fā)現(xiàn),不太對(duì)勁,它先創(chuàng)建了user表,接著又把它給刪了,還大言不慚地打印了成功信息(我的環(huán)境下是這樣,不清楚別人會(huì)不會(huì),但既然發(fā)生了就說(shuō)明存在一定的問(wèn)題)。嘗試反復(fù)執(zhí)行knex示例和seuelize示例,前者永遠(yuǎn)正確,后者永遠(yuǎn)錯(cuò)誤,而且sequelize似乎更慢一點(diǎn),產(chǎn)生這樣的區(qū)別,可能是它們執(zhí)行sql語(yǔ)句的實(shí)現(xiàn)機(jī)制不太一樣,花費(fèi)精力去看它源碼沒(méi)有必要,既然在這個(gè)場(chǎng)景下我們這兩個(gè)步驟有著明確的先后順序,那我們就通過(guò)async/await讓它們完全的順序執(zhí)行即可:

sqlClient.runSql = async (path)=> {
    const script = fs.readFileSync(path).toString();
    console.log("Going to run a sql file:");
    console.log(script);
    /**
     * 拆成一句句sql來(lái)執(zhí)行是因?yàn)?,knex執(zhí)行一串語(yǔ)句時(shí),會(huì)把它們都算進(jìn)一個(gè)事務(wù)內(nèi)
     * 忽略注釋
     * 去首尾空格
     * 按冒號(hào)分句
     * 校驗(yàn)字串是否為sql語(yǔ)句
     * @type {string[]}
     */
    const sqls = script.replace(/\/\*[\s\S]*?\*\/|(--|\#)[^\r\n]*/gm, '').trim().replaceAll('\r','').split(';').filter(str=>{
        return str.trim() ? true : false;
    });
    console.log("sqls");
    console.log(sqls);
    console.log("start run:");
    for (let sql of sqls) {
        const res = await sqlClient.query(`${sql};`);
    }
}

輸出結(jié)果:

D:\Workstation\gitee-localRepo\express-demo\DatabaseInit>node index.js
Going to run a sql file:
-- 先刪除user表
DROP TABLE IF EXISTS `user`;
-- 定義表結(jié)構(gòu),并創(chuàng)建user表
CREATE TABLE `user` (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,  --自增主鍵
    name TEXT NOT NULL,
    age INTEGER NOT NULL
);

sqls
[
  'DROP TABLE IF EXISTS `user`',
  '\n' +
    '\n' +
    'CREATE TABLE `user` (\n' +
    '    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,  \n' +
    '    name TEXT NOT NULL,\n' +
    '    age INTEGER NOT NULL\n' +
    ')'
]
start run:
Server is ready on http://:::8080
Executing (default): DROP TABLE IF EXISTS `user`;
Executing (default): CREATE TABLE `user` (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    age INTEGER NOT NULL
);
Database inits successfully!

Ok!現(xiàn)在Sequelize也按照我們的意愿完成了重置user表的初始化工作


如果初始化過(guò)程中涉及嚴(yán)格的先后順序,務(wù)必做好同步流甚至回滾機(jī)制。此外,在實(shí)際項(xiàng)目中,為了項(xiàng)目的代碼規(guī)范性,應(yīng)當(dāng)將數(shù)據(jù)庫(kù)路徑,初始化腳本路徑都寫(xiě)在配置文件中,而不是像本節(jié)為了方便直接寫(xiě)在需要調(diào)用的js文件中。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-639005.html

下一節(jié)-頁(yè)面渲染

到了這里,關(guān)于【Express.js】數(shù)據(jù)庫(kù)初始化的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包