sql操作sqlite3_exec

本文介绍如何通过使用SQLite事务来显著提高大量数据插入时的数据库操作效率,并提供了具体的代码示例。

执行sql操作sqlite3_exec用法

原型:

1 int sqlite3_exec(
2   sqlite3* ppDb,                             /* An open database */
3   const char *sql,                           /* SQL to be evaluated */
4   int (*callback)(void*,int,char**,char**),  /* Callback function */
5   void *,                                    /* 1st argument to callback */
6   char **errmsg                              /* Error msg written here */
7 );

SQLite的数据库本质上来讲就是一个磁盘上的文件,所以一切的数据库操作其实都会转化为对文件的操作,而频繁的文件操作将会是一个很好时的过程,会极大地影响数据库存取的速度。
例如:向数据库中插入100万条数据,在默认的情况下如果仅仅是执行 
sqlite3_exec(db, “insert into name values ‘lxkxf', ‘24'; ”, 0, 0, &zErrMsg); 
将会重复的打开关闭数据库文件100万次,所以速度当然会很慢。因此对于这种情况我们应该使用“事务”。 
具体方法如下:在执行SQL语句之前和SQL语句执行完毕之后加上 
rc = sqlite3_exec(db, "BEGIN;", 0, 0, &zErrMsg); 
//执行SQL语句 
rc = sqlite3_exec(db, "COMMIT;", 0, 0, &zErrMsg);
这样SQLite将把全部要执行的SQL语句先缓存在内存当中,然后等到COMMIT的时候一次性的写入数据库,这样数据库文件只被打开关闭了一次,效率自然大大的提高。有一组数据对比:
测试1: 1000 INSERTs 
CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100)); 
INSERT INTO t1 VALUES(1,13153,'thirteen thousand one hundred fifty three'); 
INSERT INTO t1 VALUES(2,75560,'seventy five thousand five hundred sixty'); 
... 995 lines omitted 
INSERT INTO t1 VALUES(998,66289,'sixty six thousand two hundred eighty nine'); 
INSERT INTO t1 VALUES(999,24322,'twenty four thousand three hundred twenty two'); 
INSERT INTO t1 VALUES(1000,94142,'ninety four thousand one hundred forty two'); 
SQLite 2.7.6: 
13.061 
SQLite 2.7.6 (nosync): 
0.223

测试2: 使用事务 25000 INSERTs 
BEGIN; 
CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100)); 
INSERT INTO t2 VALUES(1,59672,'fifty nine thousand six hundred seventy two'); 
... 24997 lines omitted 
INSERT INTO t2 VALUES(24999,89569,'eighty nine thousand five hundred sixty nine'); 
INSERT INTO t2 VALUES(25000,94666,'ninety four thousand six hundred sixty six'); 
COMMIT; 
SQLite 2.7.6: 
0.914 
SQLite 2.7.6 (nosync): 
0.757

可见使用了事务之后却是极大的提高了数据库的效率。但是我们也要注意,使用事务也是有一定的开销的,所以对于数据量很小的操作可以不必使用,以免造成而外的消耗。

android中的方法,

解决方法:

添加事务处理,把5000条插入作为一个事务

dataBase.beginTransaction();        //手动设置开始事务

//数据插入操作循环

dataBase.setTransactionSuccessful();        //设置事务处理成功,不设置会自动回滚不提交

dataBase.endTransaction();        //处理完成 




PS,在android中一般是使用 ContentResolver来包装下sqlite,自带一个批量插入的方法
public final int bulkInsert (Uri url, ContentValues[] values)
Since:  API Level 1

Inserts multiple rows into a table at the given URL. This function make no guarantees about the atomicity of the insertions.

Parameters
urlThe URL of the table to insert into.
valuesThe initial values for the newly inserted rows. The key is the column name for the field. Passing null will create an empty row.
Returns
  • the number of newly created rows. 


<think>我们被要求使用中文回答问题,并需要在回答后提出3-5个相关问题,且以“§§相关问题§§”开头,问题之间用数字序号列出,禁止换行分散。 问题:sqlite3_step和sqlite3_exec的区别 首先,我们需要回顾SQLite C API中这两个函数的区别。 1. **sqlite3_exec**: - 这是一个封装函数,用于执行一个或多个SQL语句。 - 它内部实际上调用了`sqlite3_prepare_v2`,`sqlite3_step`和`sqlite3_finalize`。 - 适用于执行不需要返回结果集的操作(如INSERT, UPDATE, DELETE, CREATE等)或者执行多个SQL语句(用分号分隔)。 - 它还可以提供一个回调函数来处理查询结果(如果有的话)。 2. **sqlite3_step**: - 用于逐步执行由`sqlite3_prepare_v2`(或类似函数)准备好的语句。 - 每次调用`sqlite3_step`,语句就会执行一步,直到成。对于查询语句,每次调用会返回一行结果,直到没有更多行(返回SQLITE_DONE)。 - 通常用于需要处理结果集的情况(如SELECT语句),可以逐行获取数据。 主要区别总结: - `sqlite3_exec`是一个高级别的便捷函数,用于执行SQL命令,特别是那些不需要返回结果集或者只需要简单回调处理结果集的命令。 - `sqlite3_step`是底层函数,需要与`sqlite3_prepare_v2`和`sqlite3_finalize`配合使用,用于更灵活地控制SQL语句执行,尤其是当需要逐行处理查询结果时。 为了更清晰,我们用一个对比表格: | 特性 | sqlite3_exec | sqlite3_step | |----------------|------------------------------------------|-----------------------------------------------| | 功能 | 执行整个SQL语句(可能多个) | 单步执行已准备的语句 | | 结果处理 | 通过回调函数(如果有结果) | 需要手动调用获取每一列数据 | | 使用复杂度 | 简单,一行代码执行操作 | 较复杂,需要准备、步进和清理 | | 灵活性 | 较低,适合简单操作 | 高,可以控制执行过程,适合复杂查询 | | 是否自动处理语句生命周期 | 是(内部准备和清理) | 否(需要显式准备和清理) | | 适用场景 | 执行DDL或不需要返回结果集的DML语句 | 需要处理结果集的查询语句 | 代码示例: 使用sqlite3_exec执行一条INSERT语句: ```c int rc = sqlite3_exec(db, "INSERT INTO table (col) VALUES (&#39;value&#39;);", NULL, NULL, &errmsg); ``` 使用sqlite3_step执行一条SELECT语句: ```c sqlite3_stmt *stmt; const char *sql = "SELECT id, name FROM table;"; rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { int id = sqlite3_column_int(stmt, 0); const char *name = (const char*)sqlite3_column_text(stmt, 1); // 处理数据 } sqlite3_finalize(stmt); ``` 注意事项: - 使用`sqlite3_step`时,必须检查返回值(SQLITE_ROW, SQLITE_DONE, 或错误代码)。 - 在循环中处理每一行数据时,注意内存管理,尤其是TEXT和BLOB类型的数据可能需要复制。 - 使用`sqlite3_exec`时,如果SQL语句包含多个语句,它会依次执行所有语句。而`sqlite3_step`一次只处理一个语句。 §§相关问题§§ 1. 在SQLite C API中,如何正确处理sqlite3_step返回的错误代码? 2. 使用sqlite3_exec时如何处理多行结果集? 3. sqlite3_prepare_v2和sqlite3_prepare有什么区别? 4. 使用sqlite3_step执行INSERT语句后如何获取插入行的ROWID? 5. 在多线程环境下使用这两个函数需要注意什么? </think>### SQLite中 `sqlite3_step` 与 `sqlite3_exec` 的区别 在 SQLite 的 C/C++ API 中,`sqlite3_step` 和 `sqlite3_exec` 是执行 SQL 语句的核心函数,主要区别如下: #### 1. **功能层级** | 函数 | 层级 | 功能描述 | |------------------|------------|--------------------------------------------------------------------------| | `sqlite3_exec` | **高级封装** | 一次性执行SQL 语句(含预处理、执行、资源清理) | | `sqlite3_step` | **底层操作** | 单步执行已预编译的语句(需配合 `sqlite3_prepare_v2` 使用) | #### 2. **执行流程对比** **`sqlite3_exec` 内部实现伪代码**: ```c int sqlite3_exec( sqlite3* db, const char* sql, int (*callback)(void*,int,char**,char**), void* data, char** errmsg ) { sqlite3_stmt* stmt; // 1. 自动编译SQL语句 sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); // 2. 循环执行所有步骤 while (sqlite3_step(stmt) == SQLITE_ROW) { // 若有回调函数则处理结果行 if(callback) callback(data, ...); } // 3. 自动释放资源 sqlite3_finalize(stmt); return SQLITE_OK; } ``` **`sqlite3_step` 典型用法**: ```c // 1. 手动预编译语句 sqlite3_prepare_v2(db, "SELECT * FROM users", -1, &stmt, NULL); // 2. 手动逐行获取结果 while (sqlite3_step(stmt) == SQLITE_ROW) { int id = sqlite3_column_int(stmt, 0); const char* name = (const char*)sqlite3_column_text(stmt, 1); } // 3. 手动释放资源 sqlite3_finalize(stmt); ``` #### 3. **关键差异总结** | 特性 | `sqlite3_exec` | `sqlite3_step` | |--------------------|---------------------------------|---------------------------------| | **结果集处理** | 通过回调函数返回所有结果 | 需手动循环获取每一行数据 | | **资源管理** | 自动释放语句句柄 | 需手动调用 `sqlite3_finalize` | | **执行效率** | 适合简单操作(无需结果处理) | 适合批量数据处理 | | **错误控制** | 通过 `errmsg` 返回单一错误 | 每步均可检查详细错误码 | | **适用场景** | DDL/简单DML(如CREATE, INSERT) | 查询/需逐行处理的复杂操作 | #### 4. **性能注意事项** - **`sqlite3_exec` 开销**:每次调用需重复编译 SQL,频繁使用时有性能损耗 - **`sqlite3_step` 优化**:预编译语句可复用(使用 `sqlite3_reset`),适合循环操作: ```c sqlite3_prepare_v2(db, "INSERT INTO logs(msg) VALUES(?)", -1, &stmt, NULL); for(int i=0; i<1000; i++) { sqlite3_bind_text(stmt, 1, log_messages[i], -1, SQLITE_STATIC); sqlite3_step(stmt); // 执行插入 sqlite3_reset(stmt); // 重置语句状态 } sqlite3_finalize(stmt); ``` #### 5. **错误处理对比** - **`sqlite3_exec`**:通过 `errmsg` 获取错误字符串,但丢失具体错误码 - **`sqlite3_step`**:直接返回错误代码(如 `SQLITE_CONSTRAINT`),可精准处理: ```c int rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { printf("Error code: %d, Message: %s\n", rc, sqlite3_errmsg(db)); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值