SQLite批量插入和其他一些使用心得

 SQLite是我在客户端上使用得最多的数据库,方便易用稳定强大,其支持很多的平台和语言:我分别在Windows (C++、QT)、Android、IOS上开发过使用SQLite来保存客户端本地数据的应用。下面说说对使用SQLite的一些心得。
      1、批量插入。很多人发现使用SQLite插入大量数据的时候非常慢。我有印象刚使用SQLite的时候发现插入2000条数据(10列左右)居然要好几分钟,速度慢得令人发指。但后来发现如果是正确使用SQLite,一般这是在小几百毫秒就能完成的工作。要点:
      A)务必要使用事务。这点可以数量级地提高批量插入的速度。
      B)使用Statement并用好,具体地说是: prepare(此步奏只运行一次) -> (开始处理第一条记录) -> bind(填充第一列) -> bind(填充第二列……) -> execute(执行插入) -> clearBind(别忘了清除填充的数据) ->  (开始处理第二条记录)  -> bind(填充第一列) -> bind (填充第二列……)-> execute -> clearBind(清除填充的数据) -> (处理第三条记录……)。Statement的prepare也是一个比较耗时的操作,在批量插入的时候没必要每次都去调用。这点对性能的提升没有使用事务来得明显,但一般也能提升几倍的性能。
      2、数据库升级机制。产品周期较长的软件开发过程中,难免要对数据库的表结构进行修改,比如增加表、字段、索引。一开始我是通过表名来进行区分,比如用户表是t_user,如果表结构需要修改就建立一张新表t_user_v2。在数据库打开的时候,检查各表是否存在,如果不存在则创建。后面开发安卓应用,发现Google的解决方法优雅多了:其可以为数据库定义一个版本号(举个栗子——19),之后如果数据库表结构需要修改,则增加这个版本号(举个栗子——增加到20)。然后在打开数据库的时候会自动触发 void onUpgrade(SQLiteDatabase db, int oldVersion[=19], int newVersion[=20] ) 函数,该函数有之前的版本号和目前的版本号,然后就可以执行相应的数据库升级脚本了。
      这套机制即使SDK没有自带,实现起来也很简单:就是在数据库初始化或者升级后找个地方保存版本记录(建议参考安卓用SQLite的user_version设置,详见:http://sqlite.org/pragma.html#pragma_schema_version,或者用SharedPreference、文本文件也是可以的。)。下次打开数据库的时候,对比保存的版本和当前的数据库版本。如果当前的数据库版本更高,则调用数据库升级函数进行升级(记得之后更新版本记录为新的版本号)。我在IOS上就是使用这种方式来进行数据库升级的。
      3、数据库划分。建议:如果没有事务、外键等需要,尽量把不同用途的表划分在多个数据库文件中,而不是使用单一的数据库文件。这么做最主要优点是有利于模块划分,避免其他所有模块都要访问同一个巨大务必的数据库模块。另外性能也会更好,比如SQLite并不支持多线程读写,所以访问同一个数据库的时候是要加同步锁的。使用多个数据库可以降低锁等待的可能。
      4、理解rowid。
       rowid是SQLite比较有特色的功能。rowid是SQLite为每条记录保存的一个隐藏列(select * from table 查看不了,需要的 select rowid,* from table),rowid从1开始递增。如果拿rowid作为外键来使用的时候,需要注意的一点是:“insert or replace into" 是会改变rowid的值。所以如果想更新记录,应该使用update语句,如果想忽略新值,应该用"insert or ignore into"语句。
      最后但很重要的是:掌握SQL的基本知识。推荐一本书:《SQL反模式》。SQL是很简单,但用久了发现里面还是有不少门道。磨刀不误砍柴工,多看一本书,也许就可以少犯很多错。

SQLite 是一个轻量级的嵌入式数据库系统,非常适合资源受限的环境。在 C++ 中进行 SQLite 批量插入可以通过以下步骤实现: 1. 首先确保你的系统已经安装了 SQLite,并且你的 C++ 环境配置了相应的库文件。 2. 打开数据库连接:使用 `sqlite3_open` 函数打开或创建一个数据库文件。 3. 准备 SQL 插入语句:编写包含占位符(如 `?`)的 SQL 插入语句,以便后续执行参数化查询。 4. 打开事务:为了提高批量插入的效率,可以先开启一个事务,这样可以在完成所有插入后再一次性提交。 5. 执行批量插入操作:通过循环,使用 `sqlite3_prepare_v2` 和 `sqlite3_bind_*` 系列函数绑定参数,然后使用 `sqlite3_step` 执行插入。重复此过程直到所有数据被插入。 6. 提交事务:完成所有插入操作后,通过 `sqlite3_commit` 提交事务。 7. 关闭数据库:最后,使用 `sqlite3_close` 关闭数据库连接。 示例代码可能如下所示: ```cpp #include <sqlite3.h> #include <iostream> int main() { sqlite3 *db; char *errMsg = nullptr; const char *sql; int rc; // 打开数据库连接 rc = sqlite3_open("example.db", &db); if (rc) { std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << std::endl; return 1; } // 开启事务 if (sqlite3_exec(db, "BEGIN TRANSACTION;", nullptr, nullptr, &errMsg) != SQLITE_OK) { std::cerr << "事务开启失败: " << errMsg << std::endl; sqlite3_free(errMsg); sqlite3_close(db); return 1; } // 准备 SQL 插入语句 sql = "INSERT INTO table_name (column1, column2) VALUES (?, ?);"; // 执行批量插入操作 sqlite3_stmt *stmt; if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) { std::cerr << "准备语句失败: " << sqlite3_errmsg(db) << std::endl; sqlite3_close(db); return 1; } for (int i = 0; i < 1000; ++i) { // 假设我们要插入1000条数据 sqlite3_bind_int(stmt, 1, i); // 绑定第一个参数 sqlite3_bind_text(stmt, 2, "data", -1, SQLITE_TRANSIENT); // 绑定第二个参数 // 执行插入操作 rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { std::cerr << "插入失败: " << sqlite3_errmsg(db) << std::endl; } sqlite3_reset(stmt); // 重置语句 } // 提交事务 if (sqlite3_exec(db, "COMMIT;", nullptr, nullptr, &errMsg) != SQLITE_OK) { std::cerr << "事务提交失败: " << errMsg << std::endl; sqlite3_free(errMsg); } // 清理 sqlite3_finalize(stmt); sqlite3_close(db); return 0; } ``` 在上面的示例代码中,我们创建了一个名为 `table_name` 的表,并且使用了两个参数进行批量插入。这里我们假设要插入1000条数据,你可以根据实际需要调整循环的次数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值