Bootstrap

uniapp云打包app使用sqlite实现本地缓存,以及云打包sqlite不生效踩坑记录

一、uniapp中使用sqlite

1.什么是sqlite

SQLite是一种轻量级的关系型数据库管理系统。它是一个自包含、无服务器的数据库引擎,可以在客户端程序中直接嵌入,并且不需要独立的数据库服务器进程。SQLite使用简单的SQL语言,支持大多数标准的SQL语法和功能,包括事务、索引和触发器等。SQLite的数据库以单个文件的形式存储在主机文件系统中,可以轻松地将数据库文件在不同的设备间进行传输和共享。由于其小巧、快速、灵活和可移植的特性,SQLite广泛用于各种嵌入式系统、移动应用程序和其他小型项目中。

2.如何在uniapp中使用sqlite

这是h5+的教学文档:https://www.html5plus.org/doc/zh_cn/sqlite.html

这是我借鉴别人封装后的sqlite模块
sqlite.js

module.exports = {
  dbName: "security", // 数据库名称
  dbPath: "_doc/security.db", // 数据库地址,推荐以下划线为开头   _doc/xxx.db

  // 判断数据库是否打开
  isOpen() {
    // 数据库打开了就返回 true,否则返回 false
    var open = plus.sqlite.isOpenDatabase({
      name: this.dbName, // 数据库名称
      path: this.dbPath, // 数据库地址
    });
    return open;
  },

  // 创建数据库 或 有该数据库就打开
  openSqlite() {
    return new Promise((resolve, reject) => {
      // 打开数据库
      plus.sqlite.openDatabase({
        name: this.dbName,
        path: this.dbPath,
        success(e) {
          resolve(e); // 成功回调
        },
        fail(e) {
          reject(e); // 失败回调
        },
      });
    });
  },

  // 关闭数据库
  closeSqlite() {
    return new Promise((resolve, reject) => {
      plus.sqlite.closeDatabase({
        name: this.dbName,
        success(e) {
          resolve(e);
        },
        fail(e) {
          reject(e);
        },
      });
    });
  },

  // 数据库建表 sql:'CREATE TABLE IF NOT EXISTS dbTable("id" varchar(50),"name" TEXT)
  // 创建 CREATE TABLE IF NOT EXISTS 、 dbTable 是表名,不能用数字开头、括号里是表格的表头
  createTable(dbTable, data) {
    return new Promise((resolve, reject) => {
      // executeSql: 执行增删改等操作的SQL语句
      plus.sqlite.executeSql({
        name: this.dbName,
        sql: `CREATE TABLE IF NOT EXISTS ${dbTable}(${data})`,
        success(e) {
          resolve(e);
        },
        fail(e) {
          reject(e);
        },
      });
    });
  },

  // 数据库删表 sql:'DROP TABLE dbTable'
  dropTable(dbTable) {
    return new Promise((resolve, reject) => {
      plus.sqlite.executeSql({
        name: this.dbName,
        sql: `DROP TABLE ${dbTable}`,
        success(e) {
          resolve(e);
        },
        fail(e) {
          reject(e);
        },
      });
    });
  },

  // 向表格里添加数据 sql:'INSERT INTO dbTable VALUES('x','x','x')'   对应新增
  // 或者 sql:'INSERT INTO dbTable ('x','x','x') VALUES('x','x','x')'   具体新增
  // 插入 INSERT INTO  、 dbTable 是表名、根据表头列名插入列值
  insertTableData(dbTable, data, condition) {
    // 判断有没有传参
    if (dbTable !== undefined && data !== undefined) {
      // 判断传的参是否有值
      var bol = JSON.stringify(data) == "{}";
      if (!bol) {
        if (condition == undefined) {
          var sql = `INSERT INTO ${dbTable} VALUES('${data}')`;
        } else {
          var sql = `INSERT INTO ${dbTable} (${condition}) VALUES(${data})`;
        }
        // console.log(sql);
        return new Promise((resolve, reject) => {
          // 表格添加数据
          plus.sqlite.executeSql({
            name: this.dbName,
            sql: sql,
            success(e) {
              resolve(e);
            },
            fail(e) {
              reject(e);
            },
          });
        });
      } else {
        return new Promise((resolve, reject) => {
          reject("错误添加");
        });
      }
    } else {
      return new Promise((resolve, reject) => {
        reject("错误添加");
      });
    }
  },

  // 根据条件向表格里添加数据  有数据更新、无数据插入
  // (建表时需要设置主键) 例如 --- "roomid" varchar(50) PRIMARY KEY
  insertOrReplaceData(dbTable, data, condition) {
    // 判断有没有传参
    if (dbTable !== undefined && data !== undefined) {
      if (condition == undefined) {
        var sql = `INSERT OR REPLACE INTO ${dbTable} VALUES('${data}')`;
      } else {
        var sql = `INSERT OR REPLACE INTO ${dbTable} (${condition}) VALUES(${data})`;
      }
      // console.log(sql);
      return new Promise((resolve, reject) => {
        // 表格添加数据
        plus.sqlite.executeSql({
          name: this.dbName,
          sql: sql,
          success(e) {
            resolve(e);
          },
          fail(e) {
            reject(e);
          },
        });
      });
    } else {
      return new Promise((resolve, reject) => {
        reject("错误添加");
      });
    }
  },

  // 查询获取数据库里的数据 sql:'SELECT * FROM dbTable WHERE lname = 'lvalue''
  // 查询 SELECT * FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值
  selectTableData(dbTable, lname, lvalue, cc, dd) {
    if (dbTable !== undefined) {
      // 第一个是表单名称,后两个参数是列表名,用来检索
      if (lname !== undefined && cc !== undefined) {
        // 两个检索条件
        var sql = `SELECT * FROM ${dbTable} WHERE ${lname} = '${lvalue}' AND ${cc} = '${dd}'`;
      }
      if (lname !== undefined && cc == undefined) {
        console.log('是否条件查询')
        // 一个检索条件
        var sql = `SELECT * FROM ${dbTable} WHERE ${lname} = '${lvalue}'`;
        console.log(sql);
      }
      if (lname == undefined) {
        var sql = `SELECT * FROM ${dbTable}`;
      }
      return new Promise((resolve, reject) => {
        // 表格查询数据  执行查询的SQL语句
        plus.sqlite.selectSql({
          name: this.dbName,
          sql: sql,
          success(e) {
            resolve(e);
          },
          fail(e) {
            reject(e);
          },
        });
      });
    } else {
      return new Promise((resolve, reject) => {
        reject("错误查询");
      });
    }
  },

  // 删除表里的数据 sql:'DELETE FROM dbTable WHERE lname = 'lvalue''
  // 删除 DELETE FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值
  deleteTableData(dbTable, lname, lvalue, ww, ee) {
    if (dbTable !== undefined) {
      if (lname == undefined) {
        var sql = `DELETE FROM ${dbTable}`;
      } else {
        if (ww !== undefined) {
          // 两个检索条件
          var sql = `DELETE FROM ${dbTable} WHERE ${lname} = '${lvalue}' AND ${ww} = '${ee}'`;
        } else {
          // 一个检索条件
          var sql = `DELETE FROM ${dbTable} WHERE ${lname} = '${lvalue}'`;
        }
      }
      return new Promise((resolve, reject) => {
        // 删除表数据
        plus.sqlite.executeSql({
          name: this.dbName,
          sql: sql,
          success(e) {
            resolve(e);
          },
          fail(e) {
            reject(e);
          },
        });
      });
    } else {
      return new Promise((resolve, reject) => {
        reject("错误删除");
      });
    }
  },

  // 修改数据表里的数据 sql:"UPDATE dbTable SET 列名 = '列值',列名 = '列值' WHERE lname = 'lvalue'"
  // 修改 UPDATE 、 dbTable 是表名, data: 要修改的列名=修改后列值, lname,lvalue 是查询条件的列名和列值
  updateTableData(dbTable, data, lname, lvalue) {
    if (lname == undefined) {
      var sql = `UPDATE ${dbTable} SET ${data}`;
    } else {
      var sql = `UPDATE ${dbTable} SET ${data} WHERE ${lname} = '${lvalue}'`;
    }
    // WHERE 前面是要修改的列名、列值,后面是条件的列名、列值
    return new Promise((resolve, reject) => {
      // 修改表数据
      plus.sqlite.executeSql({
        name: this.dbName,
        sql: sql,
        success(e) {
          resolve(e);
        },
        fail(e) {
          reject(e);
        },
      });
    });
  },

  // 获取指定数据条数  sql:"SELECT * FROM dbTable ORDER BY 'id' DESC LIMIT 15 OFFSET 'num'"
  // dbTable 表名, ORDER BY 代表排序默认正序, id 是排序的条件 DESC 代表倒序,从最后一条数据开始拿
  // LIMIT 15 OFFSET '${num}',这句的意思是跳过 num 条拿 15 条数据, num 为跳过多少条数据是动态值
  // 例 初始num设为0,就从最后的数据开始拿15条,下次不拿刚获取的数据,所以可以让num为15,这样就能一步一步的拿完所有的数据
  pullSQL(dbTable,pageNum=1, pageSize=5, key1, value1 ) {
    let start = (pageNum - 1) * pageSize;
    let size = pageSize;
    let sql = ''
    if (key1 && value1) {
      sql = `SELECT * FROM ${dbTable} WHERE ${key1} = '${value1}' ORDER BY time DESC LIMIT '${size}' OFFSET '${start}'`;  
    }else {
      sql = `SELECT * FROM ${dbTable} ORDER BY time DESC LIMIT '${size}' OFFSET '${start}'`;
    }
    return new Promise((resolve, reject) => {
      plus.sqlite.selectSql({
        name: this.dbName,
        sql: sql,
        success(e) {
          resolve(e);
        },
        fail(e) {
          reject(e);
        },
      });
    });
  },
};

这是基于上面的sqlite.js二次封装的sqlite_mixin.js
operateSqlite.js

import DB from "@/common/util/sqlite.js";

const sqobj = {
  data() {
    return {
      listData: [],
    };
  },
  methods: {
    // 打开数据库
    openSQL() {
      // 这个是查询有没有打开数据库
      let open = DB.isOpen();
      console.log("数据库状态", open ? "开启" : "关闭");
      if (!open) {
        DB.openSqlite()
          .then((res) => {
            console.log("数据库已打开");
          })
          .catch((error) => {
            console.log("数据库开启失败");
          });
      }
    },
    // 关闭数据库
    closeSQL() {
      // 这个是查询有没有打开数据库
      let open = DB.isOpen();
      if (open) {
        DB.closeSqlite()
          .then((res) => {
            console.log("数据库已关闭");
          })
          .catch((error) => {
            console.log("数据库关闭失败");
          });
      }
    },
    // 创建表
    createTable(tableName, sql) {
      console.log('创建表', tableName)
      let open = DB.isOpen();
      if (open) {
        this.openSQL();
        // let sql = '"id" INTEGER PRIMARY KEY AUTOINCREMENT,"name" text,"content" text,"time" text';
        // 创建表 DB.createTable(表名, 表的列)
        DB.createTable(tableName, sql)
          .then((res) => {
            console.log(`创建${tableName}表成功`);
            this.showToast(`创建${tableName}表成功`);
          })
          .catch((error) => {
            console.log("创建表失败");
          });
      } else {
        console.log("数据库未打开");
      }
    },
    // 删除表
    dropTable(tableName){
      let open = DB.isOpen();
      if (open) {
        // 删除表 DB.dropTable(表名)
        DB.dropTable(tableName)
          .then((res) => {
            console.log(`删除${tableName}表成功`);
          })
          .catch((error) => {
            console.log("删除表失败");
          });
      } else {
        console.log("数据库未打开");
      }
    },
    // 新增表数据
    insertTableData(tableName,arr, sql, condition) {
      console.log('插入表数据', arr)
      this.feng.showTips('插入表数据', "none", 1000);
      let open = DB.isOpen();
      if (open) {
        arr.map((item) => {
          //   let time = this.formatDate(new Date().getTime());
          //   let sql = `'${item.name}','${item.content}','${time}'`;
          //   let condition = "'name','content','time'";
          // 新增 DB.insertTableData(表名, 对应表头列的数据)
          DB.insertOrReplaceData(tableName, sql, condition)
            .then((res) => {
              console.log("新增数据成功");
              this.feng.showTips('本地保存成功', "none", 3000);
              this.selectTableData(tableName);
            })
            .catch((error) => {
              console.log("失败", error);
            });
        });
      } else {
        console.log("数据库未打开");
      }
    },
    // 查询表数据
    selectTableData(tableName, key, value) {
      let open = DB.isOpen();
      if (open) {
        // 查询表 DB.selectTableData(表名,查询条件列名,查询条件列值)
        console.log('查询表数据', tableName, key, value)
        if (key && value) {
          return new Promise((resolve, reject) => {
            DB.selectTableData(tableName, key, value)
              .then((res) => {
                console.log(`按照条件${key}查询的${tableName}表数据`, res);
                resolve(res)
              })
              .catch((error) => {
                console.log("查询失败", error);
                reject(error)
              });
          });
        } else {
          DB.selectTableData(tableName)
            .then((res) => {
              console.log(`${tableName}表数据`, res);
            })
            .catch((error) => {
              console.log("查询失败", error);
            });
        }
      } else {
        console.log("数据库未打开");
      }
    },
    // 分页查询表数据
    selectTableDataByPage(tableName, page, size, key, value) {
      let open = DB.isOpen();
      if (open) {
        // 分页查询表 DB.selectTableDataByPage(表名,查询条件列名,查询条件列值,页码,每页条数)
        if (key && value) {
          DB.pullSQL(tableName, key, value, page, size)
            .then((res) => {
              console.log(`分页按照条件${key}查询的${tableName}表数据`, res);
              this.listData = res;
            })
            .catch((error) => {
              console.log("查询失败", error);
            });
        } else {
          DB.pullSQL(tableName, page, size)
            .then((res) => {
              console.log(`分页查询${tableName}表数据`, res);
              this.listData = res;
            })
            .catch((error) => {
              console.log("查询失败", error);
            });
        }
      } else {
        console.log("数据库未打开");
      }
    },
    // 删除表数据
    deleteTableData(tableName, key, value) {
      let open = DB.isOpen();
      if (open) {
        // 删除表 DB.deleteTableData(表名,查询条件列名,查询条件列值)
        if (key && value) {
          DB.deleteTableData(tableName, key, value)
            .then((res) => {
              console.log("删除表数据成功");
              // this.selectTableData(tableName);
            })
            .catch((error) => {
              console.log("删除失败", error);
            });
        } else {
          DB.deleteTableData(tableName)
            .then((res) => {
              console.log("删除表数据成功");
              // this.selectTableData(tableName);
            })
            .catch((error) => {
              console.log("删除失败", error);
            });
        }
      } else {
        console.log("数据库未打开");
      }
    },
    // 提示框
    showToast: function (str) {
      uni.showToast({
        icon: "none",
        title: str,
        mask: true,
      });
    },
    // 时间戳转年月日
    formatDate(data) {
      let now = new Date(data);
      var year = now.getFullYear(); //取得4位数的年份
      var month =
          now.getMonth() + 1 < 10 ?
              "0" + (now.getMonth() + 1) :
              now.getMonth() + 1;
      var date = now.getDate() < 10 ? "0" + now.getDate() : now.getDate();
      var hour = now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
      var minute =
          now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
      var second =
          now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
      return (
          year +
          "-" +
          month +
          "-" +
          date +
          " " +
          hour +
          ":" +
          minute +
          ":" +
          second
      );
    }
  },
};

export default sqobj;

在页面中使用sqlite

  1. 引入mixin
<script>
import sqObj from '@/mixin/operateSqlite.js'
export default {
	mixins: [sqObj],
</script>
  1. 打开数据库,创建表
<script>
import uniRequest from "uni-request";
import bus from "@/common/util/bus.js";
import sqObj from '@/mixin/operateSqlite.js'
export default {
	components: {},
	mixins: [sqObj],
	created(){
	    this.openSQL()  // 打开数据库
		this.creatTable() // 创建security表
    },
    creatTable(){
		let sql =
            '"id" INTEGER PRIMARY KEY AUTOINCREMENT,"name" text,"age" number,"time" text';
			this.createTable("security", sql); // 创建表
	}
  1. 剩下的增删改查就不一一列举了,很简单,只需要根据需要写sql就可以了,和上面的创建表操作基本一样。

二、云打包sqlite的坑

1. sqlite模块找不到

在这里插入图片描述
在真机调试的时候可以正常使用sqlite,但是云打包app之后报上面这个错
解决方案
在hubuildx中点击manifest.json->app模块配置->勾选SQLite模块
在这里插入图片描述
这是云打包解决方案,离线打包可以看看这位大佬写的解决方案https://blog.csdn.net/qq_37021104/article/details/107382209

2. 勾选了模块,打包之后sqlite不生效。

1. 可能是db文件的存储路径问题,具体如下:

在这里插入图片描述
路径推荐使用_doc/xxx.db,_doc目录下支持读写操作。

2. 可能没有自动创建库文件

在这里插入图片描述
具体解决方案可以参考:https://ask.dcloud.net.cn/article/35729

document.addEventListener('plusready', function(e){  
    // 确保_doc/test.db文件存在  
    plus.io.requestFileSystem( plus.io.PRIVATE_DOC, function(fs){  
        fs.root.getFile('test.db', {create:true}, function(fileEntry){  
            console.log('ensure test.db file!');  
            // 打开数据库,创建表等等操作。。。
        });  
    });  
}, false);  

3. 在onload钩子中创建表不执行,放在created中

我开始是这么写的

onLoad() {
    console.log("onload哈哈哈哈");
        this.openSQL();
        let sql =
            '"id" INTEGER PRIMARY KEY AUTOINCREMENT,"name" text,"age" number,"time" text';
			this.createTable("security", sql); // 创建表
  },

不清楚为什么不执行,console都可以打印,就不不走this.createTable,改为created就好了

;