Hướng dẫn sqlite nodejs - sqlite nodejs

Hướng dẫn sqlite nodejs - sqlite nodejs

Trong bài này, mình sẽ trình bày cách sử dụng Node.js kết hợp với SQLite 3 để thêm sửa xóa các bản ghi Database dạng CSDL quan hệ (có Table, Row, Column đàng hoàng). Trước giờ NodeJS thường được dùng với No-SQL ví dụ MongoDB, JSON. Bài này sẽ sử dụng SQLite 3.

Nói thêm một chút, SQLite là một cơ sở dữ liệu quan hệ nhưng không cần server mà nó lưu trữ thành dạng file bê đi đâu cũng được ví dụ như một file word, exel vậy, rất là tiện lợi nếu cần đem phần mềm và cơ sở dữ liệu copy vào đâu cũng chạy.

Cài đặt môi trường

Mình sẽ bắt đầu bằng cách gõ lệnh

$ npm install --save bluebird
3 bên trong một thư mục mới tạo có tên là
$ npm install --save bluebird
4. Đây là lệnh để tạo mới một project bằng NodeJS. Khi chạy lệnh này thì Node sẽ hỏi chúng ta các câu hỏi cần thiết để tạo project. Ví dụ tên project, phiên bản, tác giả... Điền xong các bạn sẽ được như hình:

$ npm init
This utility will walk you through creating a package.json file.  
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields  
and exactly what they do.

Use `npm install  --save` afterwards to install a package and  
save it as a dependency in the package.json file.

Press ^C at any time to quit.  
name: (app) node-sqlite  
version: (0.0.0) 0.1.0  
description: Code for tutorial blog on node and sqlite  
entry point: (index.js) main.js  
test command:  
git repository:  
keywords:  
author: Adam McQuistan  
license: (BSD) MIT  
About to write to /node-sqlite/app/package.json:

{
  "name": "node-sqlite",
  "version": "0.1.0",
  "description": "Code for tutorial blog on node and sqlite",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": "",
  "author": "Adam McQuistan",
  "license": "MIT"
}


Is this ok? (yes) 

Tiếp theo, mình sẽ cần cài đặt gói

$ npm install --save bluebird
5 qua
$ npm install --save bluebird
6 như sau (trỏ cmd đến thư mục hiện tại và gõ như bên dưới):cmd đến thư mục hiện tại và gõ như bên dưới):

$ npm install --save sqlite3

Ngoài sqlite3 mình sẽ cài đặt

$ npm install --save bluebird
7 để mình có thể sử dụng chức năng
$ npm install --save bluebird
8 quen thuộc trong lập trình Javascript (giúp thao tác với dữ liệu).
$ npm install --save bluebird
7
để mình có thể sử dụng chức năng
$ npm install --save bluebird
8
quen thuộc trong lập trình Javascript (giúp thao tác với dữ liệu).

$ npm install --save bluebird

Bây giờ mình sẽ tạo một file trống ngay bên cạnh tệp

$ npm install --save bluebird
9 gọi là
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
0 nơi SQLite sẽ lưu trữ dữ liệu trong đó.

Thiết kế CSDL

Để lưu trữ dữ liệu cho bài toán mình sẽ thiết kế một mẫu dữ liệu quan hệ gồm 2 bảng nối nhau, kiểu master-detail.

Giả sử mình cần tạo một ứng dụng dùng để quản lý dự án. Mỗi dự án có thể có một hoặc nhiều task cần hoàn thành, cần biết rõ task hoàn thành hay chưa. Mình có thể demo dữ liệu trong bảng như sau:

Bảng projects

idname
1 Write Node.js - SQLite Tutorial
2 Testing Functionalities

Bảng tasks

idnameWrite Node.js - SQLite Tutorial Testing Functionalities Bảng tasks
1 descriptionisCompleted1 1
2 projectIdOutline 0 1

High level overview of sections

Write

Write article contents and code examples

Ok, bây giờ mình biết dữ liệu gồm những gì, giờ hãy đi tạo bảng SQL để chứa được dữ liệu của 2 bảng trên

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)

Tạo ra file Cơ sở dữ liệu

Để bắt đầu, mình sẽ cần tạo một file

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
1 cùng với file
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
2 (Toàn bộ hàm thêm sửa xóa sẽ viết chung trong đây cho gọn) trong cùng thư mục với file
$ npm install --save bluebird
9 (thư mục gốc của project).
: Được sử dụng để tạo hoặc thay đổi bảng và chèn hoặc cập nhật dữ liệu bảng.

Bên trong

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
2 mình sẽ thêm một hàm khởi tạo để kết nối đến một file sqlite3 có sẵn sử dụng Bluebird . Hàm khởi tạo này sẽ được gán vào một biến dùng chung cố định là
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
5. Hàm khởi tạo này cũng sẽ được đưa vào class
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
6 để export nó ra bên ngoài (cho phép các class khác ở file khác có thể nhìn thấy và gọi hàm khởi tạo class, từ khóa export trong js tương đương từ khóa public trong lập trình hướng đối tượng).
: Chọn một hàng dữ liệu từ một hoặc nhiều bảng.

Việc kết nối đến cơ sở dữ liệu đã được mô tả bằng các comment bên trên. Cơ bản thì bạn khởi tạo một class AppDAO và đưa đường dẫn đến tệp cơ sở dữ liệu SQLite mà bạn muốn kết nối, bạn sẽ được một biến this.db để bắt đầu thao tác với CSDL. Biến this.db này đã kế thừa đầy đủ các hàm viết sẵn của Node.js sqlite3 giúp thực thi các truy vấn (query) đến file dbFilePath. Trong ví dụ này chúng ta sẽ dùng đến 3 hàm sau đây: : Chọn nhiều hàng dữ liệu từ một hoặc nhiều bảng.

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
7: Được sử dụng để tạo hoặc thay đổi bảng và chèn hoặc cập nhật dữ liệu bảng.

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
8: Chọn một hàng dữ liệu từ một hoặc nhiều bảng.

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
9 : Chọn nhiều hàng dữ liệu từ một hoặc nhiều bảng.

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  // Đoạn code constructor trước đó

  runquery(sql, params = []) {  //Hàm do ta tự đặt tên gồm 2 tham số truyền vào.
    return new Promise((resolve, reject) => {   //Tạo mới một Promise thực thi câu lệnh sql
      this.db.run(sql, params, function (err) {   //this.db sẽ là biến đã kết nối csdl, ta gọi hàm run của this.db chính là gọi hàm run của sqlite3 trong NodeJS hỗ trợ (1 trong 3 hàm như đã nói ở trên)
        if (err) {   //Trường hợp lỗi
          console.log('Error running sql ' + sql)
          console.log(err)
          reject(err)
        } else {   //Trường hợp chạy query thành công
          resolve({ id: this.lastID })   //Trả về kết quả là một object có id lấy từ DB.
        }
      })
    })
  }
}

Để bắt đầu, hãy khám phá hàm

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
7. Cú pháp của nó như sau:

Tham số đầu tiên được truyền cho run (...) là một chuỗi SQL được thực thi và là tham số bắt buộc. Tham số thứ hai là một mảng tham số tùy chọn mà thư viện sqlite3 sẽ hoán đổi cho bất kỳ ký tự

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
1 trong tham số truyền vào. Tham số thứ 3 là một hàm callback để bắn ra lỗi nếu có lỗi sau khi thực thi.

Để áp dụng vào class AppDAO của chúng ta mình sẻ dùng đến Promise của Javascript để đặt một lệnh

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
7 query và đợi kết quả trả về. Hàm được viết thêm vào file AppDAO như sau:

// project_repository.js

class ProjectRepository { 
  constructor(dao) {      //Đểkhởi tạo một đối tượng từ class ProjectRepository chúng ta cần truyền một đối tượng AppDAO cho nó
    this.dao = dao
  }

  createTable() {   //Hàm tạo bảng này sẽ dùng để tạo ra cấu trúc bảng projects nếu trong file csdl sqlite3 chưa có bảng này.
    const sql = `
    CREATE TABLE IF NOT EXISTS projects (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT)`
    return this.dao.runquery(sql)
  }
}

Như vậy là từ bây giờ chúng ta có thể gọi hàm AppDAO.runquery(...) và truyền vào 2 tham số cho nó để nó chạy kết nối đến db và lấy ra dữ liệu cần thiết cho mình, tùy thuộc vào câu sql truyền vào.

// task_repository.js

class TaskRepository {  
  constructor(dao) {
    this.dao = dao
  }

  createTable() {
    const sql = `
      CREATE TABLE IF NOT EXISTS tasks (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        description TEXT,
        isComplete INTEGER DEFAULT 0,
        projectId INTEGER,
        CONSTRAINT tasks_fk_projectId FOREIGN KEY (projectId)
          REFERENCES projects(id) ON UPDATE CASCADE ON DELETE CASCADE)`
    return this.dao.runquery(sql)
  }
}

Như vậy là query SQL để tạo bảng đã hoàn tất, tiếp đến mình sẽ chuyển sang các hàm chèn dữ liệu vào các bảng.

Chèn dữ liệu

Trong class

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
8, mình cần thêm một hàm create nhận tên của dự án để tạo và thực thi câu lệnh INSERT thích hợp bằng AppDAO.runquery(...). Lưu ý cách mình đã sử dụng '?' để đại diện cho giá trị cho tên của dự án và sau đó đặt tham số name trong tham số mảng params tùy chọn vào hàm runquery(...). Đây là viết theo kiểu câu lệnh truy vấn được tham số hóa, nó sẽ nhận sql đầu vào để giảm thiểu rủi ro bị tấn công bằng SQL injection.

// project_repository.js

class ProjectRepository {  
  // các hàm đã viết trước đó

  create(name) {
    return this.dao.runquery(
      'INSERT INTO projects (name) VALUES (?)',
      [name])
  }
}

Một hàm khởi tạo tương tự cho class

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  // Đoạn code constructor trước đó

  runquery(sql, params = []) {  //Hàm do ta tự đặt tên gồm 2 tham số truyền vào.
    return new Promise((resolve, reject) => {   //Tạo mới một Promise thực thi câu lệnh sql
      this.db.run(sql, params, function (err) {   //this.db sẽ là biến đã kết nối csdl, ta gọi hàm run của this.db chính là gọi hàm run của sqlite3 trong NodeJS hỗ trợ (1 trong 3 hàm như đã nói ở trên)
        if (err) {   //Trường hợp lỗi
          console.log('Error running sql ' + sql)
          console.log(err)
          reject(err)
        } else {   //Trường hợp chạy query thành công
          resolve({ id: this.lastID })   //Trả về kết quả là một object có id lấy từ DB.
        }
      })
    })
  }
}
5.

// task_repository.js

class TaskRepository {  
  // các hàm đã viết trước đó

  create(name, description, isComplete, projectId) {
    return this.dao.runquery(
      `INSERT INTO tasks (name, description, isComplete, projectId)
        VALUES (?, ?, ?, ?)`,
      [name, description, isComplete, projectId])
  }
}

Bây giờ chúng ta đã có thể INSERT dữ liệu vào cơ sở dữ liệu. Giờ hãy chuyển qua chức năng để cập nhật CSDL.

Cập nhật dữ liệu

Trong class ProjectRepository, mình sẽ thêm một hàm update tất cả các trường cho bản ghi cơ sở dữ liệu của project. Đầu vào cần phải biết là project nào cần được update. Sử dụng hàm AppDAO.runquery(...), như sau:

$ npm install --save sqlite3
0

Tiếp theo là thêm hàm cập nhật tương ứng vào class TaskRepository.

$ npm install --save sqlite3
1

Xóa dữ liệu

Chức năng cuối cùng cần thực hiện là xóa các bản ghi trong cơ sở dữ liệu. Đối với chức năng này mình sẽ một lần nữa sử dụng

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  // Đoạn code constructor trước đó

  runquery(sql, params = []) {  //Hàm do ta tự đặt tên gồm 2 tham số truyền vào.
    return new Promise((resolve, reject) => {   //Tạo mới một Promise thực thi câu lệnh sql
      this.db.run(sql, params, function (err) {   //this.db sẽ là biến đã kết nối csdl, ta gọi hàm run của this.db chính là gọi hàm run của sqlite3 trong NodeJS hỗ trợ (1 trong 3 hàm như đã nói ở trên)
        if (err) {   //Trường hợp lỗi
          console.log('Error running sql ' + sql)
          console.log(err)
          reject(err)
        } else {   //Trường hợp chạy query thành công
          resolve({ id: this.lastID })   //Trả về kết quả là một object có id lấy từ DB.
        }
      })
    })
  }
}
6 kết hợp với các hàm delete cho cả hai class
db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
8 và
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  // Đoạn code constructor trước đó

  runquery(sql, params = []) {  //Hàm do ta tự đặt tên gồm 2 tham số truyền vào.
    return new Promise((resolve, reject) => {   //Tạo mới một Promise thực thi câu lệnh sql
      this.db.run(sql, params, function (err) {   //this.db sẽ là biến đã kết nối csdl, ta gọi hàm run của this.db chính là gọi hàm run của sqlite3 trong NodeJS hỗ trợ (1 trong 3 hàm như đã nói ở trên)
        if (err) {   //Trường hợp lỗi
          console.log('Error running sql ' + sql)
          console.log(err)
          reject(err)
        } else {   //Trường hợp chạy query thành công
          resolve({ id: this.lastID })   //Trả về kết quả là một object có id lấy từ DB.
        }
      })
    })
  }
}
5.

Đối với

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
8 viết thêm vào như sau:

$ npm install --save sqlite3
2

Và cho

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  // Đoạn code constructor trước đó

  runquery(sql, params = []) {  //Hàm do ta tự đặt tên gồm 2 tham số truyền vào.
    return new Promise((resolve, reject) => {   //Tạo mới một Promise thực thi câu lệnh sql
      this.db.run(sql, params, function (err) {   //this.db sẽ là biến đã kết nối csdl, ta gọi hàm run của this.db chính là gọi hàm run của sqlite3 trong NodeJS hỗ trợ (1 trong 3 hàm như đã nói ở trên)
        if (err) {   //Trường hợp lỗi
          console.log('Error running sql ' + sql)
          console.log(err)
          reject(err)
        } else {   //Trường hợp chạy query thành công
          resolve({ id: this.lastID })   //Trả về kết quả là một object có id lấy từ DB.
        }
      })
    })
  }
}
5 viết như thế này:

$ npm install --save sqlite3
3

Đã xong, chúng ta đã viết xong toàn bộ các hàm THÊM, SỬA, XÓA cho cở sở dữ liệu của 2 bảng

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
3 và
db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
4. Tiếp theo, mình sẽ giới thiệu hai hàm Node.js sqlite3 có liên quan đến get và all.

Đọc dữ liệu

Để đọc dữ liệu ra từ CSDL sau khi đã được thêm vào, hàm get được sử dụng để truy xuất một dòng dữ liệu, còn hàm all được sử dụng để truy vấn nhiều dòng dữ liệu đồng thời.

Cú pháp để get như sau:

$ npm install --save sqlite3
4

Ở đây db là một đối tượng kết nối đến file sqlite3. Bạn sẽ thấy rằng cú pháp về cơ bản giống với hàm run, nhưng ở hàm callback sau khi thực thi xong query SELECT sẽ có thêm một tham số result. Tham số này là bắt buộc vì nó sẽ chứa object (dòng dữ liệu trong bảng) đã được lấy ra và vứt vào đây.

Cú pháp của hàm

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
9 về cơ bản là giống
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
8 tham số thứ hai cho hàm callback là một mảng các kết quả được truy vấn trả về, như sau:

$ npm install --save sqlite3
5

Cũng giống như mình đã làm với hàm

// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
7 sqlite3 bên trên, mình sẽ thực hiện các hàm
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
8 và
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
9 sử dụng
// project_repository.js

class ProjectRepository { 
  constructor(dao) {      //Đểkhởi tạo một đối tượng từ class ProjectRepository chúng ta cần truyền một đối tượng AppDAO cho nó
    this.dao = dao
  }

  createTable() {   //Hàm tạo bảng này sẽ dùng để tạo ra cấu trúc bảng projects nếu trong file csdl sqlite3 chưa có bảng này.
    const sql = `
    CREATE TABLE IF NOT EXISTS projects (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT)`
    return this.dao.runquery(sql)
  }
}
8 trong class
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  constructor(dbFilePath) {
    this.db = new sqlite3.Database(dbFilePath, (err) => {  //cần truyền vào một đường dẫn đến file csdl sqlite để khởi tạo một kết nối đến file để bắt đầu đọc ghi
      if (err) {
        console.log('Could not connect to database', err)   //Kết nối chưa thành công, có lỗi
      } else {
        console.log('Connected to database')   //Đã kết nối thành công và sẵn sàng để đọc ghi DB
      }
    })
  }
}

module.exports = AppDAO    //Cần phải exports (mở) cái class  này để một class bất kỳ có thể khởi tạo AppDAO và bắt đầu dùng kết nối đã được mở bên trên (biến this.db)
6 như hình dưới đây:

$ npm install --save sqlite3
6

Bây giờ mình có thể sử dụng các hàm này trong các lớp

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
8 và
// dao.js

const sqlite3 = require('sqlite3')  
const Promise = require('bluebird')

class AppDAO {  
  // Đoạn code constructor trước đó

  runquery(sql, params = []) {  //Hàm do ta tự đặt tên gồm 2 tham số truyền vào.
    return new Promise((resolve, reject) => {   //Tạo mới một Promise thực thi câu lệnh sql
      this.db.run(sql, params, function (err) {   //this.db sẽ là biến đã kết nối csdl, ta gọi hàm run của this.db chính là gọi hàm run của sqlite3 trong NodeJS hỗ trợ (1 trong 3 hàm như đã nói ở trên)
        if (err) {   //Trường hợp lỗi
          console.log('Error running sql ' + sql)
          console.log(err)
          reject(err)
        } else {   //Trường hợp chạy query thành công
          resolve({ id: this.lastID })   //Trả về kết quả là một object có id lấy từ DB.
        }
      })
    })
  }
}
5 để lấy dữ liệu từ cơ sở dữ liệu SQLite.

Để bắt đầu, mình sẽ thêm hàm

// task_repository.js

class TaskRepository {  
  constructor(dao) {
    this.dao = dao
  }

  createTable() {
    const sql = `
      CREATE TABLE IF NOT EXISTS tasks (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        description TEXT,
        isComplete INTEGER DEFAULT 0,
        projectId INTEGER,
        CONSTRAINT tasks_fk_projectId FOREIGN KEY (projectId)
          REFERENCES projects(id) ON UPDATE CASCADE ON DELETE CASCADE)`
    return this.dao.runquery(sql)
  }
}
2 cho mỗi lớp để chọn bản ghi theo id.

Trong

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
8 mình viết thêm:

$ npm install --save sqlite3
7

Để chứng minh AppDAO.all(...), mình sẽ thêm khả năng chọn tất cả các dự án cũng như tất cả các nhiệm vụ cho một dự án cụ thể.

Mã để SELECT tất cả các dự án trông như thế này:

$ npm install --save sqlite3
8

Sau đó, để chọn tất cả các nhiệm vụ cho một dự án, mình sẽ sử dụng một hàm được gọi là getTasks(projectId)dự kiến ​​id của dự án bạn muốn các nhiệm vụ.

$ npm install --save sqlite3
9

Đặt Mã truy cập dữ liệu để sử dụng Cho đến nay mình đã cơ bản tạo ra một thư viện truy cập dữ liệu cho dự án hư cấu này và ứng dụng theo dõi nhiệm vụ. Những gì mình muốn làm bây giờ là sử dụng nó để tải lên dữ liệu thử nghiệm của mình được hiển thị trong các bảng trong phần Thiết kế cơ sở dữ liệu .

Trong tập tin main.js mình sẽ muốn kéo trong AppDAO,

db.run('SOME SQL QUERY', [param1, param2], (err) => {  
  if (err) {
    console.log('ERROR!', err)
  }
})
8 và class TaskRepository qua require. Sau đó, mình sẽ sử dụng chúng để tạo ra các bảng, điền chúng với dữ liệu sau đó, lấy dữ liệu từ cơ sở dữ liệu và hiển thị tới bàn điều khiển.

$ npm install --save bluebird
0

Biên dịch và chạy hàm main bằng lệnh Node như sau:

$ npm install --save bluebird
1

Và bạn sẽ thấy kết quả như hình dưới đây. Tất cả các hàm đều đã chạy ngon.

$ npm install --save bluebird
2

Kết luận

Trong hướng dẫn này, mình đã xem lại các khái niệm cơ bản về các hàm

// task_repository.js

class TaskRepository {  
  constructor(dao) {
    this.dao = dao
  }

  createTable() {
    const sql = `
      CREATE TABLE IF NOT EXISTS tasks (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        description TEXT,
        isComplete INTEGER DEFAULT 0,
        projectId INTEGER,
        CONSTRAINT tasks_fk_projectId FOREIGN KEY (projectId)
          REFERENCES projects(id) ON UPDATE CASCADE ON DELETE CASCADE)`
    return this.dao.runquery(sql)
  }
}
5 của
// task_repository.js

class TaskRepository {  
  constructor(dao) {
    this.dao = dao
  }

  createTable() {
    const sql = `
      CREATE TABLE IF NOT EXISTS tasks (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        description TEXT,
        isComplete INTEGER DEFAULT 0,
        projectId INTEGER,
        CONSTRAINT tasks_fk_projectId FOREIGN KEY (projectId)
          REFERENCES projects(id) ON UPDATE CASCADE ON DELETE CASCADE)`
    return this.dao.runquery(sql)
  }
}
6 và đã trình bày cách bạn có thể dùng nó trong lập trình hướng đối tượng JavaScript . Và viết code theo kiểu không đồng bộ (async) dựa trên Promise để chương trình chạy nhanh hơn gọn hơn.

Như mọi khi, mình cảm ơn bạn đã đọc!

Bài này là một bài dịch, link bài gốc ở đây: http://stackabuse.com/a-sqlite-tutorial-with-node-js/