示例:
char insert_sql[128] = {0};
for (int i=0; i<10000; ++i)
{
sprintf(insert_sql, "insert into bindtest values(%d, %d)", i, i*100);
ret = sqlite3_exec(ppdb, insert_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf("insert fail\n");
break;
}
sqlite3_free(errmsg);
}
SQLite执行在一个事务中的每条语句,支持读事务和写事务。应用程序只能是在读或写事务中才能从数据库中读数据。应用程序只能在写事务中才能向数据库中写数据。应用程序不需要明确告诉SQLite去执行事务中的单个SQL语句,SQLite时自动这样做的,这是默认行为,这样的系统叫做自动提交模式。这些事务被叫做自动事务,或系统级事务。对于一个select语句,SQLite建立一个读事务,对于一个非select语句,SQLite先建立一个读事务,再把它转换成写事务。每个事务都在语句执行结束时被提交或被终止。应用程序不知道有系统事务,应用程序只是把SQL语句提交给SQLite,由SQLite再去处理关于ACID的属性,应用程序接收从SQLite执行SQL返回的结果。一个应用程序可以在相同的数据库连接上引发执行select语句(读事务)的并行执行,但是只能在一个空闲连接上引起一个非select语句(写事务)的执行。自动提交模式可能对某些应用程序来讲代价过高,尤其是那些写密集的应用程序,因为对于每一个非select语句,SQLite需要重复打开,写入,关闭日志文件。在自动提交模式中,在每条语句执行的最后,SQLite丢弃页缓冲。每条语句执行都会重新构造缓冲区,重新构造缓冲区是花费大,低效的行动,因为会调用磁盘I/O。并且,存在并发控制的开销,因为对每一句SQL语句的执行,应用程序需要重新获取和释放对数据库文件的锁。这种开销会使性能显著下降
(尤其是大型应用程序),并只能以打开一个包括了很多SQL语句的用户级别的事务来减轻这种情况(如:打开多个数据库)。应用程序可以用begin命令手动的开始一个新的事务,这种事务被称为用户级事务(或用户事务)。当begin执行后,SQLite离开默认的自动提交模式,在语句结束时不会调用commit或abort。也不会丢弃该页的缓冲。连续的SQL语句是整个事物的一部分,当应用程序执行commit/respectively/rollback指令时,SQLite提交或分别或中止事务。如果当事务中止或失败,或应用程序关闭连接,则整个事务回滚。SQLite在事务完成时恢复到自动提交模式上来。
begin | 开始事务 |
commit | 保存更改 |
rollback | 回滚所作的更改 |
事务回滚
sqlite> select * from stu;
0|小黑
1|小白
sqlite> update stu set name='人类';
sqlite> select * from stu;
0|人类
1|人类
sqlite> rollback;
sqlite> select * from stu;
0|小黑
1|小白
事务提交
sqlite> select * from stu;
0|小黑
1|小白
sqlite> begin;
sqlite> select * from stu;
0|小黑
1|小白
sqlite> update stu set name='人类';
sqlite> select * from stu;
0|人类
1|人类
sqlite> commit;
sqlite> select * from stu;
0|人类
1|人类
sqlite> rollback;
Error: cannot rollback - no transaction is active
编程实验:事务对插入效率的影响
#include <stdio.h>
#include <sqlite3.h>
#include <time.h>
int main()
{
// 1. 打开数据库
sqlite3 *ppdb = NULL;
int ret = sqlite3_open("test.db", &ppdb);
if (ret != SQLITE_OK)
{
printf("open fail\n");
return -1;
}
// 2. 执行 sql 语句
// 2.1 创建表格 create table apitest(id int, number int);
const char *create_sql = "create table if not exists testTransaction(id int, number int)";
char *errmsg = NULL;
ret = sqlite3_exec(ppdb, create_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf("%s\n", errmsg);
}
sqlite3_free(errmsg);
// 2.2 数据直接插入 ==============================
struct timeval start;
struct timeval end;
char insert_sql[128] = {0};
mingw_gettimeofday(&start, NULL);
for (int i=0; i<1000; ++i)
{
sprintf(insert_sql, "insert into testTransaction values(%d, %d)", i, i*100);
ret = sqlite3_exec(ppdb, insert_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf("insert fail\n");
break;
}
sqlite3_free(errmsg);
}
mingw_gettimeofday(&end, NULL);
printf("insert directly: %ld s\n", end.tv_sec - start.tv_sec);
// 2.3 数据直接插入-事务 ==============================
mingw_gettimeofday(&start, NULL);
sqlite3_exec(ppdb, "begin", NULL, NULL, NULL);
for (int i=0; i<1000; ++i)
{
sprintf(insert_sql, "insert into testTransaction values(%d, %d)", i, i*100);
ret = sqlite3_exec(ppdb, insert_sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf("insert fail\n");
break;
}
sqlite3_free(errmsg);
}
sqlite3_exec(ppdb, "commit", NULL, NULL, NULL);
mingw_gettimeofday(&end, NULL);
printf("insert directly(transaction): %ld us\n", end.tv_usec - start.tv_usec);
// 3. 关闭数据库
ret = sqlite3_close(ppdb);
if (ret != SQLITE_OK)
{
printf("close fail\n");
return -1;
}
return 0;
}
输出:
insert directly: 7 s
insert directly(transaction): 10996 us
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。