electron-vue开发笔记(5)集成sqlite数据库

4,395 阅读7分钟

准备写个系列,先把flag立上~

安装

npm install sqlite3 --save

使用

参考

数据库操作

连接

import sqlite3 from 'sqlite3'
const sqlite = process.env.NODE_ENV === 'development' ? sqlite3.verbose() : sqlite3
db = new sqlite.Database(db_path, callback)

sqlite3需要注意区分是否为发布环境,verbose模式下可以打印堆栈信息,便于调试。

关闭

db.close()

常用 API 封装

promise 封装

run (sql, params = []) {
  return new Promise((resolve, reject) => {
    this.db.run(sql, params, (err) => {
      if (err) {
        console.log('Error running sql: ' + sql + ' params: ' + params)
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

exec (sql) {
  return new Promise((resolve, reject) => {
    this.db.exec(sql, (err) => {
      if (err) {
        console.log('Error running sql: ', sql)
        reject(err)
      } else {
        resolve()
      }
    })
  })
}

get (sql, params = []) {
  return new Promise((resolve, reject) => {
    this.db.get(sql, params, (err, data) => {
      if (err) {
        console.log('Error running sql: ' + sql + ' params: ' + params)
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

all (sql, params = []) {
  return new Promise((resolve, reject) => {
    this.db.all(sql, params, (err, data) => {
      if (err) {
        console.log('Error running sql: ' + sql + ' params: ' + params)
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

async await 封装

在github上找到一个封装好的库 sqlite-async

示例

  • 抓了掘金首页feed的数据,提前插入5条feed记录,用于演示sql的操作,以下为sql文件。
// sqlite.sql
-- 创建数据表
-- recommend
CREATE TABLE IF NOT EXISTS welcome (
   id             TEXT PRIMARY KEY NOT NULL,
   commentsCount  INTEGER COMMENT '评论数',
   likeCount      INTEGER COMMENT '点赞数',
   originalUrl    TEXT COMMENT '文章链接',
   content        TEXT COMMENT '文章摘要',
   category       TEXT COMMENT '文章类别',
   tags           TEXT COMMENT '文章标签, 多个用逗号分隔',
   title          TEXT COMMENT '文章标题',
   user           TEXT COMMENT '作者',
   createdAt      TEXT COMMENT '创建时间',
   updatedAt      TEXT COMMENT '修改时间'
);

-- category
CREATE TABLE IF NOT EXISTS category (
   id             TEXT PRIMARY KEY NOT NULL,
   name           TEXT COMMENT '名称'
);

-- tag
CREATE TABLE IF NOT EXISTS tag (
   id             TEXT PRIMARY KEY NOT NULL,
   title          TEXT COMMENT '名称'
);

-- user
CREATE TABLE IF NOT EXISTS user (
   id             TEXT PRIMARY KEY NOT NULL,
   role           TEXT COMMENT '角色',
   avatarLarge    TEXT COMMENT '头像',
   username       TEXT COMMENT '用户名'
);

-- 初始数据
INSERT OR REPLACE INTO category (id, name) VALUES ('5562b415e4b00c57d9b94ac8', '前端');
INSERT OR REPLACE INTO category (id, name) VALUES ('5562b428e4b00c57d9b94b9d', '阅读');
INSERT OR REPLACE INTO category (id, name) VALUES ('5562b405e4b00c57d9b94a41', 'iOS');
INSERT OR REPLACE INTO category (id, name) VALUES ('5562b419e4b00c57d9b94ae2', '后端');

INSERT OR REPLACE INTO tag (id, title) VALUES ('555e9a98e4b00c57d9955f68', 'Vue.js');
INSERT OR REPLACE INTO tag (id, title) VALUES ('55964d83e4b08a686cc6b353', 'JavaScript');
INSERT OR REPLACE INTO tag (id, title) VALUES ('55e7d00800b0c86e8e693ef4', 'HTTP');
INSERT OR REPLACE INTO tag (id, title) VALUES ('5bfcde44f265da3ff4cc84cf', 'HTTP3');
INSERT OR REPLACE INTO tag (id, title) VALUES ('559e7cc0e4b0796c19675383', 'Swift');
INSERT OR REPLACE INTO tag (id, title) VALUES ('5a96291f6fb9a0535b535438', 'Flutter');
INSERT OR REPLACE INTO tag (id, title) VALUES ('57029a6971cfe4005cd12757', '阿里巴巴');
INSERT OR REPLACE INTO tag (id, title) VALUES ('5b6cffe9f265da1b969e30f2', '云原生');

INSERT OR REPLACE INTO user (id, role, avatarLarge, username) VALUES ('57e60c005bbb50005d51d852', 'guest', 'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/7/11/1733c56f84384f0f~tplv-t2oaga2asx-image.image', '前端进击者');
INSERT OR REPLACE INTO user (id, role, avatarLarge, username) VALUES ('5e477d7ce51d4526c550a27d', 'guest', 'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/7/8/1732ee33bc6d7dc6~tplv-t2oaga2asx-image.image', '魔王哪吒');
INSERT OR REPLACE INTO user (id, role, avatarLarge, username) VALUES ('591ea3c32f301e006becc1bc', 'guest', "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/mirror-assets/168e084cb9e78362b6b~tplv-t2oaga2asx-image.image", "吕小鸣");
INSERT OR REPLACE INTO user (id, role, avatarLarge, username) VALUES ('5a52075e6fb9a01c9d31b107', 'editor', "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/3/7/16956cee70a4bd79~tplv-t2oaga2asx-image.image", "老司机技术周报");
INSERT OR REPLACE INTO user (id, role, avatarLarge, username) VALUES ('5ad01d036fb9a028d444fc82', 'guest', "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/5/17/16ac4dafd827d7b7~tplv-t2oaga2asx-image.image", "阿里巴巴云原生");

INSERT OR REPLACE INTO welcome (id, commentsCount, likeCount, originalUrl, content, category, tags, title, user, createdAt, updatedAt) 
VALUES ('5f0b99c9e51d4534c14db4e7', 45, 308, "https://juejin.cn/post/6850037262441250829", "在前面的文章中,小编为大家带来了许多Vue 实战技巧,也得到了大家的许多好评。其实在前面那些技巧之外,我们还可以做的更多,让我们的开发流程更流畅,开发体验更好,项目性能更上一层楼,怎么做呢,我们一起来看看。 在我们开发的时候,为了方便调试,我们需要使用源码进行调试,但在生产环境…", "5562b415e4b00c57d9b94ac8", "555e9a98e4b00c57d9955f68,55964d83e4b08a686cc6b353", "我在项目中是这样配置Vue的", "57e60c005bbb50005d51d852", "2020-07-12T23:16:25.114Z", "2020-07-13T08:45:03.025Z");
INSERT OR REPLACE INTO welcome (id, commentsCount, likeCount, originalUrl, content, category, tags, title, user, createdAt, updatedAt) 
VALUES ('5f0bb6d7e51d45346c510566', 145, 248, "https://juejin.cn/post/6850037263116533773", "计算机网络知识,是面试常考的内容,在实际工作中也常常会涉及到。 http0.9只是一个简单的协议,只有一个GET方法,没有首部,目标用来获取HTML。 HTTP1.0协议大量内容:首部,响应码,重定向,错误,条件请求,内容编码等。 因为不足缺陷,就有了http1.1。 http…", "5562b415e4b00c57d9b94ac8", "55e7d00800b0c86e8e693ef4", "14期-连肝7个晚上,总结了计算机网络的知识点!(共66条)", "5e477d7ce51d4526c550a27d", "2020-07-13T02:57:25.075Z", "2020-07-13T08:44:56.402Z");
INSERT OR REPLACE INTO welcome (id, commentsCount, likeCount, originalUrl, content, category, tags, title, user, createdAt, updatedAt) 
VALUES ('5f0bde54f265da22e93e5cd0', 125, 268, "https://juejin.cn/post/6850418105462571021", "HTTP3.0,也称作HTTP over QUIC。核心是QUIC(读音quick)协议,由Google在2015年提出的SPDY v3演化而来的新协议,传统的HTTP协议是基于传输层TCP的协议,而QUIC是基于传输层UDP上的协议,可以定义成:HTTP3.0基于UDP的安全…", "5562b428e4b00c57d9b94b9d", "5bfcde44f265da3ff4cc84cf", "在Nginx中支持HTTP3.0/QUIC", "591ea3c32f301e006becc1bc", "2020-07-13T08:27:00.324Z", "2020-07-13T08:45:02.837Z");
INSERT OR REPLACE INTO welcome (id, commentsCount, likeCount, originalUrl, content, category, tags, title, user, createdAt, updatedAt) 
VALUES ('5f0c124a5188252e98364dfb', 325, 568, "https://juejin.cn/post/6850037277754834957", "老司机 iOS 周报,只为你呈现有价值的信息。 你也可以为这个项目出一份力,如果发现有价值的信息、文章、工具等可以到 Issues 里提给我们,我们会尽快处理。记得写上推荐的理由哦。有建议和意见也欢迎到 Issues 提出。 热烈欢迎周报团队的第 33 个编辑 - @JonyF…", "5562b405e4b00c57d9b94a41", "559e7cc0e4b0796c19675383,5a96291f6fb9a0535b535438", "老司机 iOS 周报 #119 | 2020-07.13", "5a52075e6fb9a01c9d31b107", "2020-07-13T07:50:34.817Z", "2020-07-13T08:45:02.774Z");
INSERT OR REPLACE INTO welcome (id, commentsCount, likeCount, originalUrl, content, category, tags, title, user, createdAt, updatedAt) 
VALUES ('5f0c09ac6fb9a07eac066e4c', 365, 268, "https://juejin.cn/post/6850418107920416776", "毕业时间为 2020 年 11 月- 2021-10 月海内外高校的全日制本科、硕士、博士。 关注开源技术,有开源贡献者优先。 下面跟你说说阿里云那么多团队,为什么你要来云原生团队。 云原生团队诞生了 Apache RocketMQ、Apache Dubbo、Spring Cl…", "5562b419e4b00c57d9b94ae2", "57029a6971cfe4005cd12757,5b6cffe9f265da1b969e30f2", "长话短说,阿里云原生团队招人,急", "5ad01d036fb9a028d444fc82", "2020-07-13T07:13:48.701Z", "2020-07-13T08:44:57.059Z");

  • 数据库初始化
createTables () {
  return new Promise((resolve, reject) => {
    const filePath = path.join(__dirname, '/sqlite.sql')
    fs.readFile(filePath, 'utf-8').then((sql, err) => {
      if (err) {
        console.log('Readfile err: ', err)
        reject(err)
      } else {
        this.exec(sql)
          .then(() => resolve())
          .catch((err) => reject(err))
      }
    })
  })
}
  • 创建api/welcome.js封装对feed的接口
// welcome.js
/**
 * 从数据库读取缓存推荐列表
 *
 * @param {Object}  req
 * @param {String}  req.title       文章标题,根据文章标题模糊查询
 * @param {uint}    req.pageNum     分页参数 页数
 * @param {uint}    req.pageSize    分页参数 每页显示条数
 */
async function getWelcomeListLocal_ (req) {
  console.log('getWelcomeListLocal', JSON.stringify(req))

  if (!req || !Common.isNumber(req.pageNum) ||
  !Common.isNumber(req.pageSize)) {
    return {
      errCode: -1,
      errMsg: '参数缺失或格式不正确'
    }
  }

  const pageNum = req.pageNum
  const pageSize = req.pageSize
  const start = pageSize * (pageNum - 1)
  let condition = ``
  const condArr = []

  if (req.title) {
    condition += ' and title like ?'
    condArr.push('%' + req.title + '%')
  }
  condition += ` order by createdAt limit ${pageSize} offset ${start}`

  let sql = `select * from welcome where 1=1 ${condition}`
  console.log('getWelcomeListLocal', sql, JSON.stringify(condArr))
  const results = await db.all(sql, condArr)
  return Promise.all(
    results.map(async item => {
      const categoryPromise = db.get('select * from category where id = ?', [item.category])
      const tags = item.tags.split(',').map(item => { return ('"' + item + '"') }).join(',')
      const tagPromise = await db.all('select * from tag where id in (' + tags + ')', [])
      const userPromise = await db.get('select * from user where id = ?', [item.user])
      Promise.all([categoryPromise, tagPromise, userPromise]).then(values => {
        item.category = values[0]
        item.tags = values[1]
        item.user = values[2]
      })
      return item
    })
  )
}

/**
 * 从数据库中删除一条welcome记录
 *
 * @param {Object} req
 * @param {String} req.id 记录id
 */
function deleteWelcome (req) {
  console.log('deleteWelcome', JSON.stringify(req))
  let sql = `delete from welcome where id = '${req.id}'`
  return db.exec(sql)
}