sqlite3使用

c库:

下载地址:SQLite Download Page

交叉编译工具编译出错:

-->WARNING: 'aclocal-1.15' is missing on your system

sudo apt install automake-1.15

-->sqlite3-shell.o: file not recognized: File format not recognized

是因为我在pc端点一了这个文件,make clean以下即可

23.获得自增字段当前值。

CREATE TABLE mytable (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);
insert into mytable (name) values('n1');
insert into mytable (name) values('n2');
select seq from sqlite_sequence WHERE name = 'mytable';

20.错误:code:1,sql = begin, msg: cannot start a transaction within a transaction

用SQLite3在同一个数据库里面同时操作三个表单table,使用事务模式插入数据,提示2个错误Error cannot start a transaction within a transaction。

21:跨表查询:select * from tabmaster where mkey not in (select mkey from tabsub);

22:数据库瘦身,数据库添加很多数据后,清空后,文件还是很大,可以通过这个方式瘦身:VACUUM table_name;

1、打开关闭

sqlite3_open,sqlite3_close

2、执行命令:

sqlite3_exec

3、select语句得到返回用:

sqlite3_get_table,sqlite3_free_table

4、另外一个好用的接口:

sqlite3_prepare,sqlite3_bind_blob(), sqlite3_step(通过判断返回值为SQLITE_ROW得到所有数据), sqlite3_finalize

参考:sqlite3:深入理解sqlite3_stmt 机制_猪哥-嵌入式的博客-CSDN博客_sqlite3_stmt

sqlite3_stmt *stmt;

stringstream getcmd;

string tmpstr;

int sqlrst = 0, preResult = 0;

getcmd << "insert into mytable (id, name, score, picture) values ("<< usrid << ", 张三, " << inputScore << ",?);";//如果要用sqlite3_bind_,要使用“?”来代替。

tmpstr = getcmd.str();

getcmd.str("");

coutdbg << tmpstr << endl;

preResult = sqlite3_prepare(dbwork, tmpstr.c_str(), tmpstr.length(), &stmt, 0);

sqlite3_bind_blob(stmt, 1, featurebuf, len, NULL);//可以为sql语句中的"?"填数据,1代表第一个?

sqlrst = sqlite3_step(stmt);//如果有多行数据,返回SQLITE_ROW,正常返回SQLITE_DONE

sqlite3_finalize(stmt);

5、错误#define SQLITE_MISUSE 21

一般是我们sql语句有问题,或者没有对应的表格,问题一般都是我们的问题。

6、未解之谜:#define SQLITE_ERROR 1 和14错误

我一直执行sql语句,发现我insert 1018 条语句后,报这个错误,后面都不能再次插入数据,我尝试sqlite3_close+sqlite3_open结果打开失败,重新运行程序从1019条继续插入却不会报这个错误!(出错后使用sqlite3_exec+sqlite3_get_table暂时没发现错误)我使用新建数据库和新建表格不会出现上面的错误

7.sqlite3效率问题:

参考:Sqlite3性能测试_哲这这的博客-CSDN博客_sqlite性能测试

同异步处理的优劣势,数据损坏问题:Sqlite3的synchronous的模式选择_chinaclock的博客-CSDN博客_sqlite synchronous

打开与关闭同步操作,关闭同步,我执行多条(非批量操作)insert或delete效果提升10倍。但是可能出现数据库损坏,所以sqlite3并没有默认打开!

int tableOptionClassDefine::optSetSyncPragma(int syncflag)

{

string sqlstr;

if(syncflag)

{

sqlstr = "PRAGMA synchronous = NO;";

}

else

{

sqlstr = "PRAGMA synchronous = OFF;";

}

int rst;

rst = sqlite3_exec(sodb, sqlstr.c_str(), NULL, NULL, &sqlite_error_msg);

}

使用事务:在批量操作时,效果极为突出,提高上几十倍效率,并且此时同异步不起太大作用。

在sqlite内部有锁机制,同一时间只有一个写操作,不用担心同时写有问题,控制好的话也不用加外部锁。但是可能出现写超时现象,使用sqlite3_busy_timeout(optSql, 1000);等待一会。

锁死情况参考:sqlite3 多线程和锁 ,优化插入速度及性能优化 - 熠熠闪光 - 博客园

使用2次"begin"而没有对应的"commit"或者"rollback",现在2个连接都在等待对方释放锁,于是就死锁了。当然,实际情况并没那么糟糕,任何一方选择不继续等待,回滚事务就行了。

sqlite3_exec(sodb, "begin", NULL, NULL, &sqlite_error_msg);

sqlite3_exec(sodb, "commit", NULL, NULL, &sqlite_error_msg);

sqlite3_exec(sodb, "rollback", NULL, NULL, &sqlite_error_msg);回滚,失败了使用回滚

如:

sqlite3_exec(sodb, "begin", NULL, NULL, &sqlite_error_msg);

sqlstr = "insert into " SRC2_T1_TABLE_NAME " (uid, name, age, addr, photo) values (?, ?, ?, ?, ?);";

coutdbg(sqlstr);

rst = sqlite3_prepare_v2(sodb, sqlstr.c_str(), -1, &stmt, 0);

for(i = 0; i < 10000; i++)

{

tmpinfo.uid = i + 1;

tmpinfo.age = (i *1233 + 5) % 20;

tmpinfo.name = "欣" + to_string(tmpinfo.uid);

tmpinfo.addr = "锦州" + to_string(tmpinfo.uid);

setPicVal(tmpinfo, tmpinfo.uid);

sqlite3_reset(stmt);

sqlite3_bind_int(stmt, 1, tmpinfo.uid);

sqlite3_bind_text(stmt, 2, tmpinfo.name.c_str(), tmpinfo.name.size(), SQLITE_STATIC);

sqlite3_bind_int(stmt, 3, tmpinfo.age);

sqlite3_bind_text(stmt, 4, tmpinfo.addr.c_str(), tmpinfo.addr.size(), SQLITE_STATIC);

sqlite3_bind_blob(stmt, 5, tmpinfo.pic, STUDENT_PIC_SIZE_FIXED, SQLITE_STATIC);

rst = sqlite3_step(stmt);

if(JUDEG_SQL_RESULT(rst))

{

coutdbg("err:" << rst);

break;

}

}

sqlite3_exec(sodb, "commit", NULL, NULL, &sqlite_error_msg);

sqlite3_finalize(stmt);

8.读取sqlite数据:

int tableOptionClassDefine::optGetUsrIdInform(u32 usrid, studentsInformDef *info)

{

JUDGE_OPT_DB_NULL_AND_PTR(info);

string sqlstr;

stringstream sstr;

int rst;

TAB_TRANSATION_RUN_BEGIN;

sqlite3_stmt *stmt;

sqlstr = "select uid, age, name, age, addr, photo from " SRC2_T1_TABLE_NAME " where uid = ?;";

coutdbg(sqlstr);

rst = sqlite3_prepare_v2(sodb, sqlstr.c_str(), -1, &stmt, 0);

sqlite3_reset(stmt);

sqlite3_bind_int(stmt, 1, usrid);

rst = sqlite3_step(stmt);

if(rst == SQLITE_ROW)

{

const char *picval;

info->uid = sqlite3_column_int(stmt, 0);

info->name = (const char *)sqlite3_column_text(stmt, 1);

info->age = sqlite3_column_int(stmt, 2);

info->addr = (const char *)sqlite3_column_text(stmt, 3);

picval = (const char *)sqlite3_column_blob(stmt, 4);

info->copyPic(picval, STUDENT_PIC_SIZE_FIXED);

rst = WORK_ERR_OK;

}

else

{

coutdbg("err:" << rst);

rst = SQLITE_OPT_ERR_DEFIN(rst);

}

TAB_TRANSATION_RUN_COMMIT;

sqlite3_finalize(stmt);

return rst;

}

9.我使用了联合主键(复合主键,关联主键)。

CREATE TABLE tabUserFPData (studentNumber INTEGER, age INTEGER, IdCard INTEGER,name TEXT, photo BLOB, addr TEXT, PRIMARY KEY (studentNumber, age, IdCard));

  使用IdCard查找name居然很慢,但是用studentNumber查找很快;用IdCard查找studentNumber和age快,猜测唯一主键是studentNumber,通过studentNumber查找都很快,而使用IdCard查找其他几个联合主键快。

总结:---->联合主键,第一个key=studentNumber是表的主键,而其他几个联合主键并不是表的主键,但是他们的相互查找是很快的。但是如果sex是0-1变化的,也不能起啥作用。---->如果数据库一行数据很大,比如photo文件大,会降低操作效率

10.有时候我们会遇到这种情况,我们需要插入一条语句,却不知道数据库有没有,然后就需要先select,如果找到update,没找到insert。是不是很麻烦,事务还不好操作。使用replace!可以参考Sqlite3中replace语句用法详解_昨夜星辰_zhangjg的博客-CSDN博客_sqlite的replace

  a.replace在事务情况下效率也很高!

  b.在以下两种任意一种情况下,replace将执行update。---->所有的PRIMARY KEY在表中都相同;--->被定义为UNIQUE字段相同的时候

  c.不能使用where限定。因为他有自己规则!

11.select得到很多数据的话,就算我们只取其中一条,执行时间也比较长,可以使用limit 1;来处理。 如:select * from mytable limit 1;

-->数据库字段长度不能太大,我用了8K的字段内容,并且是KEY,插入特别慢。

12.sqlite多线程操作的时候:database is locked,错误标号SQLITE_BUSY,出现上述现象的原因是SQLite支持锁,同一时刻也只能进行一个写操作。。我的问题是因为事务多次“begin”而没有commit或roolback导致锁死。参考sqlite3 多线程和锁 ,优化插入速度及性能优化 - 熠熠闪光 - 博客园

13.sqlite3_column_bytes可以获得sqlite3_column_blob数据的长度

14.获得表信息:PRAGMA table_info(mytable);

15.ALTER TABLE 'mytable' ADD 'columnName' TEXT;//添加列,sqlite3没有删除列

ALTER TABLE database_name.table_name RENAME TO new_table_name;//重命名
DROP TABLE database_name.table_name;删除表
DELETE FROM COMPANY;//清空表

16.一个新能测试:参考了网上的代码

#include <ctimer.h>


#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <list>
#include <cstdio>
 
#include "sqlite3.h"
 
// 参考:http://blog.csdn.net/majiakun1/article/details/46607163
 
static const char* kDatabaseName = "test.db";
 
//--------------------------------------------------------------
 
static void TestTimer();
 
//--------------------------------------------------------------
 
static bool PrepareDB(sqlite3** db, bool create_table);
 
static void CreateTable();
 
static void ClearTable();
 
static void TestExec(bool turn_off_synchronous = false);
 
static void TestNoSynchronous();
 
static void TestTransactionExec();
 
static void TestStep(bool turn_on_transaction = true);
 
static void PerformanceTest();
 
//--------------------------------------------------------------
 
int main() {
  //TestTimer();
  ClearTable();
  CreateTable();
 
  PerformanceTest();
 
  return 0;
}
 
//--------------------------------------------------------------
 
static void PerformanceTest() {
  ClearTable();
  TestExec(false);
  ClearTable();
  TestExec(true);
  ClearTable();
  TestNoSynchronous();
  ClearTable();
  TestTransactionExec();
  ClearTable();
  TestStep(true);
  ClearTable();
  TestStep(false);
}
 
// 1.直接执行sqlite3_exec。
static void TestExec(bool turn_off_synchronous) {
  sqlite3* db = NULL;
  if (!PrepareDB(&db, false)) {
    return;
  }
 
  if (turn_off_synchronous) {
    std::cout << "1.关闭写同步执行sqlite3_exec : " << std::endl;
  } else {
    std::cout << "2.直接执行sqlite3_exec : " << std::endl;
  }
 
  timerClass timer;
  std::stringstream sstream(std::stringstream::out);
 
  const int kDataCount = 1000;
  const char* kTurnOffSynchronous = "PRAGMA synchronous = OFF;";
  if (turn_off_synchronous) {
    sqlite3_exec(db, kTurnOffSynchronous, NULL, NULL, NULL);
  }
 
  // Insert.
  timer.Start();
  for (int i = 0; i < kDataCount; ++i) {
    sstream << "INSERT INTO PERFORMANCE_TEST VALUES("
            << i << "," << i << "," << i << "," << i << ");";
 
    sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL);
    sstream.str("");
  }

  double rate = kDataCount / timer.GetSeconds();
  std::cout << "插入数据: " << rate <<"条/秒" << std::endl;
 
  // Delete.
  timer.Start();
  for (int i = 0; i < kDataCount; ++i) {
    sstream << "DELETE FROM PERFORMANCE_TEST WHERE ID1 = " << i;
    sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL);
    sstream.str("");
  }
 
  rate = kDataCount / timer.GetSeconds();
  std::cout << "删除数据: " << rate << "条/秒\n" << std::endl;
 
  sqlite3_close(db);
}
 
// 2.显式开启事务,执行sqlite3_exec。
// (A)所谓”事务“就是指一组SQL命令,这些命令要么一起执行,要么都不被执行。
// (B)在SQLite中,每调用一次sqlite3_exec()函数,就会隐式地开启了一个事务,如果插入一条数据,就调用该函数一次,事务就会被反复地开启、关闭,会增大IO量。
// (C)如果在插入数据前显式开启事务,插入后再一起提交,则会大大提高IO效率,进而加数据快插入速度。
static void TestTransactionExec() {
  sqlite3* db = NULL;
  if (!PrepareDB(&db, false)) {
    return;
  }
 
  std::cout << "3.显式开启事务执行sqlite3_exec : " << std::endl;
 
  timerClass timer;
  std::stringstream sstream(std::stringstream::out);
 
  const int kDataCount = 100000;
  const char* kBeginTransaction = "begin";
  const char* kCommitTransaction = "commit";
 
  // Insert.
  timer.Start();
  sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL);
  for (int i = 0; i < kDataCount; ++i) {
    sstream << "INSERT INTO PERFORMANCE_TEST VALUES("
      << i << "," << i << "," << i << "," << i << ");";
 
    sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL);
    sstream.str("");
  }
  sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL);
 
  double rate = kDataCount / timer.GetSeconds();
  std::cout << "插入数据: " << rate << "条/秒" << std::endl;
 
  // Delete.
  timer.Start();
  sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL);
  for (int i = 0; i < kDataCount; ++i) {
    sstream << "DELETE FROM PERFORMANCE_TEST WHERE ID1 = " << i;
    sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL);
    sstream.str("");
  }
  sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL);
 
  rate = kDataCount / timer.GetSeconds();
  std::cout << "删除数据: " << rate << "条/秒\n" << std::endl;
 
  sqlite3_close(db);
}
 
// 3.关闭写同步且显式开启事务执行sqlite3_exec。
// (A)在SQLite中,数据库配置的参数都由编译指示(pragma)来实现的。
// (B)synchronous选项有三种可选状态,分别是full、normal、off。
// 当synchronous设置为FULL,SQLite数据库引擎在紧急时刻会暂停以确定数据已经写入磁盘。这使系统崩溃或电源出问题时能确保数据库在重起后不会损坏。FULL synchronous很安全但很慢。
// 当synchronous设置为NORMAL, SQLite数据库引擎在大部分紧急时刻会暂停,但不像FULL模式下那么频繁。 NORMAL模式下有很小的几率(但不是不存在)发生电源故障导致数据库损坏的情况。
// 但实际上,在这种情况 下很可能你的硬盘已经不能使用,或者发生了其他的不可恢复的硬件错误。
// 当为synchronous OFF时,SQLite在传递数据给系统以后直接继续而不暂停。若运行SQLite的应用程序崩溃, 数据不会损伤,但在系统崩溃或写入数据时意外断电。
// (C)SQLite3中,该选项的默认值就是full,如果我们再插入数据前将其改为off,则会提高效率。
static void TestNoSynchronous() {
  sqlite3* db = NULL;
  if (!PrepareDB(&db, false)) {
    return;
  }
 
  std::cout << "4.关闭写同步且显式开启事务执行sqlite3_exec : " << std::endl;
 
  timerClass timer;
  std::stringstream sstream(std::stringstream::out);
 
  const int kDataCount = 100000;
  const char* kTurnOffSynchronous = "PRAGMA synchronous = OFF;";
  const char* kBeginTransaction = "begin";
  const char* kCommitTransaction = "commit";
 
  sqlite3_exec(db, kTurnOffSynchronous, NULL, NULL, NULL);
 
  // Insert.
  timer.Start();
  sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL);
  for (int i = 0; i < kDataCount; ++i) {
    sstream << "INSERT INTO PERFORMANCE_TEST VALUES("
      << i << "," << i << "," << i << "," << i << ");";
 
    sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL);
    sstream.str("");
  }
  sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL);
 
  double rate = kDataCount / timer.GetSeconds();
  std::cout << "插入数据: " << rate << "条/秒" << std::endl;
 
  // Delete.
  timer.Start();
  sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL);
  for (int i = 0; i < kDataCount; ++i) {
    sstream << "DELETE FROM PERFORMANCE_TEST WHERE ID1 = " << i;
    sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL);
    sstream.str("");
  }
  sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL);
 
  rate = kDataCount / timer.GetSeconds();
  std::cout << "删除数据: " << rate << "条/秒\n" << std::endl;
 
  sqlite3_close(db);
}
 
// 4. 使用sqlite3_step执行。
// (A)SQLite执行SQL语句的时候,有两种方式:一种是使用前文提到的函数sqlite3_exec(),该函数直接调用包含SQL语句的字符串;
// 另一种方法就是“执行准备”(类似于存储过程)操作,即先将SQL语句编译好,然后再一步一步(或一行一行)地执行。
// (B)如果采用前者的话,就算开起了事务,SQLite仍然要对循环中每一句SQL语句进行“词法分析”和“语法分析”。
// (C)“执行准备”主要分为三大步骤:并且声明一个指向sqlite3_stmt对象的指针,该函数对参数化的SQL语句zSql进行编译,将编译后的状态存入ppStmt中。
// 调用函数 sqlite3_step() ,这个函数就是执行一步(本例中就是插入一行),如果函数返回的是SQLite_ROW则说明仍在继续执行,否则则说明已经执行完所有操作。
// 调用函数 sqlite3_finalize(),关闭语句。
// (D)综上所述啊,SQLite插入数据效率最快的方式就是:事务+关闭写同步+执行准备(存储过程),如果对数据库安全性有要求的话,就开启写同步。
 
static void TestStep(bool turn_on_transaction) {
  sqlite3* db = NULL;
  if (!PrepareDB(&db, false)) {
    return;
  }
 
  std::string title = "5.直接执行sqlite3_step : ";
  if (turn_on_transaction) {
    title = "6.显式开启事务执行sqlite3_step : ";
  }
 
  std::cout << title << std::endl;
 
  timerClass timer;
 
  int data_count = 1000;
  if (turn_on_transaction) {
    data_count = 100000;
  }
 
  const char* kBeginTransaction = "begin";
  const char* kCommitTransaction = "commit";
 
  // Insert.
  timer.Start();
  if (turn_on_transaction) {
    sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL);
  }
 
  const char* kInsertSql = "INSERT INTO PERFORMANCE_TEST VALUES(?,?,?,?);";
 
  sqlite3_stmt* stmt = NULL;
  sqlite3_prepare_v2(db, kInsertSql, strlen(kInsertSql), &stmt, NULL);
  for (int i = 0; i < data_count; ++i) {
    sqlite3_reset(stmt);
 
    sqlite3_bind_int(stmt, 1, i);
    sqlite3_bind_int(stmt, 2, i);
    sqlite3_bind_int(stmt, 3, i);
    sqlite3_bind_int(stmt, 4, i);
    sqlite3_step(stmt);
  }
 
  if (turn_on_transaction) {
    sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL);
  }
 
  sqlite3_finalize(stmt);
 
  double rate = data_count / timer.GetSeconds();
  std::cout << "插入数据: " << rate << "条/秒" << std::endl;
 
  // Delete.
  timer.Start();
  if (turn_on_transaction) {
    sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL);
  }
 
  const char* kDeleteSql = "DELETE FROM PERFORMANCE_TEST WHERE ID1 = ?;";
  sqlite3_prepare_v2(db, kDeleteSql, strlen(kDeleteSql), &stmt, NULL);
  for (int i = 0; i < data_count; ++i) {
    sqlite3_reset(stmt);
 
    sqlite3_bind_int(stmt, 1, i);
    sqlite3_step(stmt);
  }
 
  if (turn_on_transaction) {
    sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL);
  }
 
  sqlite3_finalize(stmt);
 
  rate = data_count / timer.GetSeconds();
  std::cout << "删除数据: " << rate << "条/秒\n" << std::endl;
 
  sqlite3_close(db);
}
 
static bool PrepareDB(sqlite3** db, bool create_table) {
  int rc = sqlite3_open(kDatabaseName, db);
  if (rc != SQLITE_OK) {
    std::cout << "Failed to open " << kDatabaseName << std::endl;
    std::cout << "Error msg: " << sqlite3_errmsg(*db) << std::endl;
    return false;
  }
 
  if (!create_table) {
    return true;
  }
 
  const char* kCreateTableSql = "CREATE TABLE PERFORMANCE_TEST(\
                                                                 ID1 INT PRIMARY KEY, ID2 INT, ID3 INT, ID4 INT\
                                                                                                  );";
  char* error_msg = NULL;
  rc = sqlite3_exec(*db, kCreateTableSql, NULL, NULL, &error_msg);
  if (rc != SQLITE_OK) {
    std::cout << "Failed to create table PERFORMANCE_TEST." << std::endl;
    std::cout << "Error msg: " << error_msg << std::endl;
    sqlite3_free(error_msg);
    return false;
  }
 
  return true;
}
 
static void CreateTable() {
  sqlite3* db = NULL;
  PrepareDB(&db, true);
  sqlite3_close(db);
}
 
static void ClearTable() {
  sqlite3* db = NULL;
  PrepareDB(&db, false);
 
  const char* kClrearTableSql = "DELETE FROM PERFORMANCE_TEST;";
  char* error_msg = NULL;
 
  int rc = sqlite3_exec(db, kClrearTableSql, NULL, NULL, &error_msg);
  if (rc != SQLITE_OK) {
    std::cout << "Failed to clear table!" << std::endl;
    std::cout << "Error msg: " << error_msg << std::endl;
    sqlite3_free(error_msg);
  }
 
  sqlite3_close(db);
}

运行结果:
2.直接执行sqlite3_exec : 
插入数据: 494.805条/秒
删除数据: 602.047条/秒

1.关闭写同步执行sqlite3_exec : 
插入数据: 8064.52条/秒
删除数据: 9009.01条/秒

4.关闭写同步且显式开启事务执行sqlite3_exec : 
插入数据: 194932条/秒
删除数据: 220264条/秒

3.显式开启事务执行sqlite3_exec : 
插入数据: 177305条/秒
删除数据: 189394条/秒

6.显式开启事务执行sqlite3_step : 
插入数据: 740741条/秒
删除数据: 649351条/秒

5.直接执行sqlite3_step : 
插入数据: 651.89条/秒
删除数据: 631.313条/秒

17.sqlite3_reset说明:对所有V3.6.23.1以及其前面的所有版本,需要在sqlite3_step()之后调用sqlite3_reset(),在后续的sqlite3_ step之前。如果调用sqlite3_reset重置准备语句失败,将会导致sqlite3_ step返回SQLITE_MISUSE,但是在V3. 6.23.1以后,sqlite3_step()将会自动调用sqlite3_reset。测试结果:在使用了insert/replace时,sqlite3_ step 后需要执行sqlite3_reset,否则报19错误

18.如果一个column被设置为了unique,经测试,他的查找也是很快的,并不需要把他放在primary key中!联合主键参考9.primary key第一个主键或者unique查找所有很快,primary key其他键查找primary key第一主键快,查找其他不快!

19.有时候会出现:SQLITE_CORRUPT (int)-----The database disk image is malformed.错误。

可能原因参考:磁盘空间不足/写入数据过程中突然掉电。

检查数据库是否有错误:

PRAGMA integrity_check;(检测数据库)或PRAGMA integrity_check(tablename);(检测数据库里面一个表)如果没有错误返回"ok"

错误的db文件参考:https://pan.baidu.com/s/1dbZKOOUDFLplisrBpSPa-Q   sjtj

或者用shell sqlit3 myusr.db .selftest

lxin@lxin-virtual-machine:~$ sqlite3 ~/workdir/nfsdir/my.db .selftest
Missing SELFTEST table - default checks only
1: Expected: [ok]
1:      Got: [*** in database main ***
On tree page 2 cell 12: Rowid 479 out of order
On tree page 2 cell 11: Rowid 445 out of order
On tree page 2 cell 10: Rowid 411 out of order
On tree page 44 cell 30: Rowid 528 out of order|row 378 missing from index sqlite_autoindex_TabOption_1|row 379 missing from index sqlite_autoindex_TabOption_1|row 380 missing from index sqlite_autoindex_TabOption_1|row 381 missing from index sqlite_autoindex_TabOption_1|row 382 missing from index sqlite_autoindex_TabOption_1|row 383 missing from index sqlite_autoindex_TabOption_1|row 384 missing from index sqlite_autoindex_TabOption_1|row 385 missing from index sqlite_autoindex_TabOption_1|row 386 missing from index sqlite_autoindex_TabOption_1|row 387 missing from index sqlite_autoindex_TabOption_1|row 388 missing from index sqlite_autoindex_TabOption_1|row 389 missing from index sqlite_autoindex_TabOption_1|row 390 missing from index sqlite_autoindex_TabOption_1|row 391 missing from index sqlite_autoindex_TabOption_1|row 392 missing from index sqlite_autoindex_TabOption_1|row 393 missing from index sqlite_autoindex_TabOption_1|row 394 missing from index sqlite_autoindex_TabOption_1|row 395 missing from index sqlite_autoindex_TabOption_1|row 396 missing from index sqlite_autoindex_TabOption_1|row 397 missing from index sqlite_autoindex_TabOption_1|row 398 missing from index sqlite_autoindex_TabOption_1|row 399 missing from index sqlite_autoindex_TabOption_1|row 400 missing from index sqlite_autoindex_TabOption_1|row 401 missing from index sqlite_autoindex_TabOption_1|row 402 missing from index sqlite_autoindex_TabOption_1|row 403 missing from index sqlite_autoindex_TabOption_1|row 404 missing from index sqlite_autoindex_TabOption_1|row 405 missing from index sqlite_autoindex_TabOption_1|row 406 missing from index sqlite_autoindex_TabOption_1|row 407 missing from index sqlite_autoindex_TabOption_1|row 408 missing from index sqlite_autoindex_TabOption_1|wrong # of entries in index sqlite_autoindex_TabOption_1]
1 errors out of 1 tests
lxin@lxin-virtual-machine:~$ sqlite3 ~/workdir/nfsdir/newdev.db .selftest
Missing SELFTEST table - default checks only
0 errors out of 1 tests
lxin@lxin-virtual-machine:~$ sqlite3 ~/workdir/nfsdir/abc.db .selftest
Missing SELFTEST table - default checks only
0 errors out of 1 tests

程序备份参考:

如果执行PRAGMA integrity_check;不是检测错误,而是文件错误"Error: database disk image is malformed"。那么使用恢复函数是没有用的,可以直接拷贝备份回来,重新打开数据库即可。

sqlite3_backup_init()
sqlite3_backup_step()
sqlite3_backup_remaining()
sqlite3_backup_pagecount()
sqlite3_backup_finish()

(1)通过命令备份数据库

    ---通过在命令行窗口下执行sqlite3.exe以重新建立和SQLite的连接。
    sqlite3 test.db
    sqlite> .backup 'c:/test.db'
    sqlite> .exit

(2)恢复数据库

    sqlite3 test.db
    sqlite> .restore 'c:/test.db'

通用str为字段的数据库设计:

#ifndef __SQLITE3_OPTION_TAB_AND_PARM_H__
#define __SQLITE3_OPTION_TAB_AND_PARM_H__
#include <types.h>
#include <sqlite3.h>
#include <jsonComOpt.h>
#include <logBaseWork.h>
#include <msgBaseWrk.h>



enum sqlite3OptErrorList
{
    sqlite3OptOk = SQLITE_OK,
    sqlite3OptDbNull = SQLITE_DONE + 1,
    sqlite3OptSqlExeErr,
    sqlite3OptJsonParseErr,
    sqlite3OptCheckErr,
    sqlite3OptErrMax
};

struct dbFileInformDef
{
    sqlite3 *dbSqlOpt;
    const char *dbfile;
    const char *bkfile;
};

#define dbSqlite3NullDect(dbopt)           \
    if (dbopt)                        \
    {                                 \
        logwerr("canot operate Null sqlite");               \
        return sqlite3OptDbNull; \
    }

class sqlite3BaseOption
{
public:
    static int openSql3DbFile(const std::string dbfile, sqlite3 **sqldbopt)
    {
        if(sqldbopt == NULL)
        {
            logwerr("save sqlite db need not null");
            return sqlite3OptDbNull;
        }
        if (*sqldbopt != nullptr)
        {
            coutdbg("already opened: " << dbfile);
            return sqlite3OptOk;
        }
        int rst = sqlite3_open(dbfile.c_str(), sqldbopt);
        if (rst != SQLITE_OK)
        {
            logwerr("Failed to open:%s", dbfile.c_str());
            logwerr("Error msg: %s", sqlite3_errmsg(*sqldbopt));
            *sqldbopt = NULL;
            return sqlite3OptDbNull;
        }
        return sqlite3OptOk;
    }

    static int closeSql3DbFile(sqlite3 **sqldbopt)
    {
        if (sqldbopt == nullptr)
        {
            return sqlite3OptOk;
        }
        if (*sqldbopt)
        {
            sqlite3_close(*sqldbopt);
            *sqldbopt = NULL;
        }
        return sqlite3OptOk;
    }

    //
    static int tabElementExist(sqlite3 *sqldbopt, std::string tableName, std::string columnName)
    {
        dbSqlite3NullDect(sqldbopt == nullptr);
        std::string sqlstr;
        int optResult = 0;
        sqlite3_stmt *stmt = NULL;
        sqlstr = "PRAGMA table_info(" + std::string(tableName) + ");";
        sqlite3_prepare_v2(sqldbopt, sqlstr.c_str(), -1, &stmt, 0);
        while (sqlite3_step(stmt) == SQLITE_ROW)
        {
            std::string nameRead = (const char *)sqlite3_column_text(stmt, 1);
            if (nameRead == columnName)
            {
                optResult = 1; // find
                break;
            }
        }
        sqlite3_finalize(stmt);
        return optResult;
    }

    static int getTabCounts(sqlite3 *sqldbopt, std::string tableName)
    {
        dbSqlite3NullDect(sqldbopt == nullptr);
        std::string sqlstr;
        int tablen = 0;
        sqlite3_stmt *stmt = NULL;
        sqlstr = "select count() from " + std::string(tableName) + ";";
        sqlite3_prepare_v2(sqldbopt, sqlstr.c_str(), -1, &stmt, 0);
        while (sqlite3_step(stmt) == SQLITE_ROW)
        {
            tablen = sqlite3_column_int(stmt, 0);
            break;
        }
        sqlite3_finalize(stmt);
        return tablen;
    }

    static int enableForeignKey(sqlite3 *sqldbopt)
    {
        dbSqlite3NullDect(sqldbopt == nullptr);
        std::string sqlstr = "PRAGMA foreign_keys = ON";
        return exeSqlite3Cmd(sqldbopt, sqlstr);
    }

    static int addTabOneElement(sqlite3 *sqldbopt, std::string TableName, std::string ColumnName, 
        std::string ColType, std::string DefaultValue)
    {
        dbSqlite3NullDect(sqldbopt == nullptr);
        std::string sqlstr;
        if (tabElementExist(sqldbopt, TableName, ColumnName))
        {
            return SQLITE_OK;
        }
        sqlstr = "ALTER TABLE '" + TableName + "' ADD '" + ColumnName + "' " + ColType + " DEFAULT('" + DefaultValue + "');";
        return exeSqlite3Cmd(sqldbopt, sqlstr);
    }

    static int exeSqlite3Cmd(sqlite3 *sqldbopt, std::string sqlstr)
    {
        dbSqlite3NullDect(sqldbopt == nullptr);
        char *tmperrmsg = nullptr;
        int tmprst = sqlite3_exec(sqldbopt, sqlstr.c_str(), NULL, NULL, &tmperrmsg);
        if (!(tmprst == SQLITE_OK || tmprst == SQLITE_DONE || tmprst == SQLITE_ROW))
        {
            coutdbg("err! code:" << tmprst << ",sql = " << sqlstr.substr(0, 200) << ", msg: " << tmperrmsg);
            tmprst = sqlite3OptSqlExeErr;
        }
        if (tmperrmsg)
        {
            sqlite3_free(tmperrmsg);
            tmperrmsg = nullptr;
        }
        return tmprst;
    }

    static int checkDbFile(sqlite3 *sqldbopt)
    {
        dbSqlite3NullDect(!sqldbopt);

        std::string sqlstr;
        int optResult = -1;
        sqlite3_stmt *stmt = NULL;
        sqlstr = "PRAGMA integrity_check;";
        sqlite3_prepare_v2(sqldbopt, sqlstr.c_str(), -1, &stmt, 0);
        int tmpflag = sqlite3_step(stmt);
        logwdbg("%d", tmpflag);
        if(tmpflag == SQLITE_ROW)
        {
            std::string checkStr = (const char *)sqlite3_column_text(stmt, 0);
            logwdbg("%s", checkStr.c_str());
            if(checkStr == "ok")
            {
                optResult = sqlite3OptOk;
            }
        }
        else
        {
            optResult = -2;
        }
        sqlite3_finalize(stmt);
        return optResult;
    }

    static int backupOrRestoreDb(struct dbFileInformDef *tfInfo, int backupflag)
    {
        dbSqlite3NullDect(!tfInfo || !tfInfo->dbSqlOpt || !tfInfo->bkfile);
        sqlite3 *dbBackup;
        sqlite3_backup *bkupUsr;
        sqlite3_open(tfInfo->bkfile, &dbBackup);
        if(!backupflag)
        {//restore
            bkupUsr = sqlite3_backup_init(tfInfo->dbSqlOpt, "main", dbBackup, "main");
        }
        else
        {//backup
            bkupUsr = sqlite3_backup_init(dbBackup, "main", tfInfo->dbSqlOpt, "main");
        }
        if(bkupUsr)
        {
            sqlite3_backup_step(bkupUsr,-1);
            sqlite3_backup_finish(bkupUsr);
        }
        logwdbg("[%d]%d,%d", backupflag, sqlite3_backup_remaining(bkupUsr), sqlite3_backup_pagecount(bkupUsr));
        sqlite3_close(dbBackup);
        return 0;
    }
    static int autoCheckBackOrRes(struct dbFileInformDef *tfInfo)
    {
        logwdbg("%p,%s,%s", tfInfo->dbSqlOpt, tfInfo->dbfile, tfInfo->bkfile);
        dbSqlite3NullDect(!tfInfo || !tfInfo->dbSqlOpt || !tfInfo->bkfile);
        int tmpflag = checkDbFile(tfInfo->dbSqlOpt);
        if(tmpflag == -1)
        {
            return backupOrRestoreDb(tfInfo, 0);
        }
        if(tmpflag == -2)
        {
            std::string tmpstr = std::string("rm -f ") + tfInfo->dbfile + "&& " + 
                "cp -f " + tfInfo->bkfile + " " + tfInfo->dbfile;
            logwdbg("%s", tmpstr.c_str());
            system(tmpstr.c_str());
            return -19999;
        }
        else
        {
            return backupOrRestoreDb(tfInfo, 1);
        }
    }

    static int dbRestore(struct dbFileInformDef *tfInfo, int forceFlag = 0)
    {
        logwdbg("%p,%s,%s", tfInfo->dbSqlOpt, tfInfo->dbfile, tfInfo->bkfile);
        dbSqlite3NullDect(!tfInfo || !tfInfo->dbSqlOpt || !tfInfo->bkfile);
        if(checkDbFile(tfInfo->dbSqlOpt) || forceFlag)
        {
            return backupOrRestoreDb(tfInfo, 0);
        }
        return 0;
    }

    static void tabDbListsInit(struct dbFileInformDef *infs, int ilen)
    {
        int i;
        if(!infs)
        {
            logwerr("");
            return;
        }
        for(i = 0; i < ilen; i++)
        {
            sqlite3BaseOption::openSql3DbFile(infs[i].dbfile, &infs[i].dbSqlOpt);
        }
    }

    static void tabDbListsInitPro(struct dbFileInformDef *infs, int ilen)
    {
        tabDbListsInit(infs, ilen);
        if(tabDbListsBackup(infs, ilen) == -19999)
        {
            logwwrn("err db, need reinit!");
            tabDbListsQuit(infs, ilen);
            tabDbListsInit(infs, ilen);
            if(tabDbListsBackup(infs, ilen) == -19999)
            {
                logwerr("cannot fixed err!");
            }
        }
    }

    static int tabDbListsBackup(struct dbFileInformDef *infs, int ilen)
    {
        int i;
        int tmpflag = 0;
        if(!infs)
        {
            logwerr("");
            return -1;
        }
        for(i = 0; i < ilen; i++)
        {
            if(autoCheckBackOrRes(&infs[i]) == -19999)
            {
                tmpflag = -19999;
            }
        }
        return tmpflag;
    }

    static void tabDbListsQuit(struct dbFileInformDef *infs, int ilen)
    {
        int i;
        if(!infs)
        {
            logwerr("");
            return;
        }
        for(i = 0; i < ilen; i++)
        {
            sqlite3BaseOption::closeSql3DbFile(&infs[i].dbSqlOpt);
        }
    }

};

//备注:此接口只实用于所有字段为字符串的表格!
struct tabFieldInitInfoDef
{
    std::string name;
    std::string specText;
    std::string defval;//默认字符串
};

struct tabStrDefBaseInfo
{
    std::string baseTabName;
    std::string baseTabPrimKey;
    const struct tabFieldInitInfoDef *baseTabCols;
    int baseTabColsLen;
    const std::string *baseTabInitCmd;
    int baseTabInitCmdLen;
    sqlite3 **baseDbHand;
};

typedef std::vector<std::string> colValsType;
typedef std::list<colValsType> tabListDataType;
class tabCacheValsClass
{
public:
    tabCacheValsClass()
    {
        cleanVals();
    }
    tabCacheValsClass(const struct tabStrDefBaseInfo *inBaseinfo)
    {
        cleanVals();
        setTabInfo(inBaseinfo);
    }
    ~tabCacheValsClass()
    {
        cleanVals();
    }
    void cleanVals()
    {
        tabBaseInfo = NULL;
        tabRowsData.clear();
    }
    int setTabInfo(const struct tabStrDefBaseInfo *inBaseinfo)
    {
        if(inBaseinfo == NULL)
        {
            logwerr("");
            return -1;
        }
        tabBaseInfo = inBaseinfo;
        return 0;
    }

    void insertOneRow(colValsType &inputVals)
    {
        if(tabBaseInfo == NULL)
        {
            logwerr("");
        }
        tabRowsData.push_back(inputVals);
    }

    int jsonToCacheData(Json::Value &jsonRoot) 
    {
        int i, j;
        // Json::StyledWriter sw;
        // cout << sw.write(jsonRoot) << endl;
        if(tabBaseInfo == NULL)
        {
            logwerr("");
            return -1;
        }
        if(tabBaseInfo->baseTabColsLen < 1 || tabBaseInfo->baseTabName == "")
        {
            logwdbg("not init");
            return sqlite3OptJsonParseErr;
        }
        if(!jsonRoot.isObject())
        {
            logwerr("");
            return sqlite3OptJsonParseErr;
        }
        Json::Value &tabVal = jsonRoot[tabBaseInfo->baseTabName];
        if(!tabVal.isObject())
        {
            logwerr("");
            return sqlite3OptJsonParseErr;
        }
        Json::Value &colsVal = tabVal["cols"];
        if(colsVal == Json::Value::null || colsVal.type() != Json::arrayValue || colsVal.size() < 1)
        {
            logwwrn("%d", colsVal.type());
            return sqlite3OptJsonParseErr;
        }
        Json::Value &rowsVal = tabVal["rows"];
        if(rowsVal == Json::Value::null || rowsVal.type() != Json::arrayValue)
        {
            logwwrn("");
            return sqlite3OptJsonParseErr;
        }
        std::vector<int> tmpColsFlag;
        for(i = 0; i < tabBaseInfo->baseTabColsLen; i++)
        {
            tmpColsFlag.push_back(-1);
            for(j = 0; j < (int)colsVal.size(); j++)
            {
                if(colsVal[j].asString() == tabBaseInfo->baseTabCols[i].name)
                {
                    tmpColsFlag[i] = j;
                }
            }
        }
        for(auto rowIter = rowsVal.begin(); rowIter != rowsVal.end(); rowIter++)
        {
            if(!rowIter->isArray())
            {
                logwerr("");
                continue;
            }
            colValsType tmpif;
            tmpif.resize(tabBaseInfo->baseTabColsLen);
            for(i = 0; i < tabBaseInfo->baseTabColsLen; i++)
            {
                if(tmpColsFlag[i] >= 0 && tmpColsFlag[i] < (int)rowIter->size())
                {
                    tmpif[i] = (*rowIter)[tmpColsFlag[i]].asString();
                }
                else
                {
                    tmpif[i] = tabBaseInfo->baseTabCols[i].defval;
                }
            }
            insertOneRow(tmpif);
        }
        return sqlite3OptOk;
    }

    int tabValsToJson(Json::Value &outRoot) 
    {
        int i;
        outRoot.clear();
        Json::Value &tabVal = outRoot[tabBaseInfo->baseTabName], colsVal;
        if(tabBaseInfo == NULL)
        {
            logwerr("");
            return -1;
        }
        if(tabBaseInfo->baseTabColsLen < 1 || tabBaseInfo->baseTabName == "")
        {
            logwdbg("not init");
            return -1;
        }
        for(i = 0; i < tabBaseInfo->baseTabColsLen; i++)
        {
            colsVal.append(tabBaseInfo->baseTabCols[i].name);
        }
        tabVal["cols"] = colsVal;
        Json::Value &rowsVal = tabVal["rows"];
        foreachCxx(tmpTableInfIter, tabRowsData)
        {
            colsVal.clear();
            for(i = 0; i < tabBaseInfo->baseTabColsLen; i++)
            {
                colsVal.append((*tmpTableInfIter)[i]);
            }
            rowsVal.append(colsVal);
        }
        // Json::StyledWriter sw;
        // cout << sw.write(outRoot) << endl;
        return tabRowsData.size();
    }

    const struct tabStrDefBaseInfo *tabBaseInfo;
    tabListDataType tabRowsData;//表数据保存
};

#define GET_ONE_TAB_DATA_ROWS (10000)
class strTabOptComClass
{
public:
    strTabOptComClass()
    {
        tabBaseInf = tabStrDefBaseInfo();
    }
    strTabOptComClass(const struct tabStrDefBaseInfo &tabinfo)
    {
        initTable(tabinfo);
    }

    ~strTabOptComClass(void)
    {
    }

    int createTable(void) 
    {
        dbSqlite3NullDect(isNotInit());
        std::string sqlstr;
        int i, optResult = 0;// NOT NULL UNIQUE AUTOINCREMENT
        sqlstr = "create table if not exists " + tabBaseInf.baseTabName + " (";
        for(i = 0; i < tabBaseInf.baseTabColsLen; i++)
        {
            if(tabBaseInf.baseTabCols[i].specText != "")
            {
                sqlstr += tabBaseInf.baseTabCols[i].name + " TEXT " + tabBaseInf.baseTabCols[i].specText + ",";
            }
            else
            {
                sqlstr += tabBaseInf.baseTabCols[i].name + " TEXT,";
            }
        }
        sqlstr += tabBaseInf.baseTabPrimKey + ");";
        logwdbg("%s", sqlstr.c_str());
        optResult = sqlite3BaseOption::exeSqlite3Cmd(*tabBaseInf.baseDbHand, sqlstr.c_str());
        if (optResult != SQLITE_OK)                                                 
        {                                                                     
            logwerr("err:%d;%s", optResult, sqlstr.c_str());
        }
        return optResult;
    }

    int initTable(const struct tabStrDefBaseInfo &tabinfo) 
    {
        tabBaseInf = tabinfo;
        if(createTable())
        {
            logwerr("");
            return -1;
        }
        sqlite3_stmt *stmt = NULL;
        std::string sqlstr;
        int optResult;
        tabCacheValsClass listusrinf;
        // logwdbg("");
        if(tabBaseInf.baseTabInitCmd && tabBaseInf.baseTabInitCmdLen > 0)
        {
            for(int i = 0; i < tabBaseInf.baseTabInitCmdLen; i++)
            {
                logwdbg("[list:%s]%s", tabBaseInf.baseTabName.c_str(), tabBaseInf.baseTabInitCmd[i].c_str());
                sqlite3BaseOption::exeSqlite3Cmd(*tabBaseInf.baseDbHand, tabBaseInf.baseTabInitCmd[i].c_str());
            }
        }
        {// sqlite3_prepare_v2 must have sqlite3_finalize with the end
            // if primary key is deferent, create new table, and copy old table
            //sqlstr = ".schema " USER_INFORM_TABLE_NAME;
            sqlstr = "select sql from sqlite_master where name = '" + tabBaseInf.baseTabName + "'";
            sqlite3_prepare_v2(*tabBaseInf.baseDbHand, sqlstr.c_str(), -1, &stmt, 0);
            optResult = -1;
            if(sqlite3_step(stmt) == SQLITE_ROW)
            {
                sqlstr = (const char *)sqlite3_column_text(stmt, 0);
                if((std::string::size_type)sqlstr.find(tabBaseInf.baseTabPrimKey) != std::string::npos)
                {
                    optResult = sqlite3OptOk;
                }
            }
            sqlite3_finalize(stmt);
        }
        if(optResult == sqlite3OptOk)
        {
            goto finishPoint;
        }
        logwwrn("");
        sqlstr = "alter table " + tabBaseInf.baseTabName + " rename to " + tabBaseInf.baseTabName + "_bak;";
        if(sqlite3BaseOption::exeSqlite3Cmd(*tabBaseInf.baseDbHand, sqlstr))
        {
            // table USER_INFORM_TABLE_NAME have to create
            //goto finishPoint;
        }
        // create new table
        createTable();
        sqlstr = "select * from " + tabBaseInf.baseTabName + "_bak;";
        getTabSelectVals(sqlstr, listusrinf);
        upTabFromCacheDatas(listusrinf);
        
        sqlstr = "drop table " + tabBaseInf.baseTabName + "_bak;";
        sqlite3BaseOption::exeSqlite3Cmd(*tabBaseInf.baseDbHand, sqlstr);
    finishPoint:
        // return optResult;
        return 0;
    }
    int isNotInit()
    {
        if(!tabBaseInf.baseDbHand || !(*tabBaseInf.baseDbHand))
        {
            logwerr("%p", tabBaseInf.baseDbHand);
            return -1;
        }
        if(tabBaseInf.baseTabName == "" || tabBaseInf.baseTabCols == nullptr || tabBaseInf.baseTabColsLen < 1)
        {
            logwerr("%s,%p,%d", tabBaseInf.baseTabName.c_str(), tabBaseInf.baseTabCols, tabBaseInf.baseTabColsLen);
            return -2;
        }
        return 0;
    }

    std::string tabName()
    {
        return tabBaseInf.baseTabName;
    }

    int getTabSelectVals(std::string sqlstr, tabCacheValsClass &outlist) 
    {
        int ret = sqlite3OptOk;
        dbSqlite3NullDect(isNotInit());
        sqlite3_stmt *stmt = NULL;
        const char *tmpColumnText;
        outlist.setTabInfo(&tabBaseInf);
        //string sqlstr;
        //sqlstr = "select * from " + tabBaseInf.baseTabName + "_bak;";
        //sqlstr = "select * from " + tabBaseInf.baseTabName + ";";
        //sqlstr = "select * from " + tabBaseInf.baseTabName + " where FingerId == 1;";   
        // logwdbg("%s", sqlstr.c_str());
        sqlite3_prepare_v2(*tabBaseInf.baseDbHand, sqlstr.c_str(), -1, &stmt, 0);
        while(sqlite3_step(stmt) == SQLITE_ROW)
        {
            colValsType tmpRowVals;
            // logwdbg("%d,%d", outlist.tabColsCount, sqlite3_column_count(stmt));
            for(int i = 0; i < tabBaseInf.baseTabColsLen; i++)
            {
                tmpColumnText = (const char *)sqlite3_column_text(stmt, i);
                if(tmpColumnText)
                {
                    tmpRowVals.push_back(tmpColumnText);
                }
                else
                {
                    tmpRowVals.push_back("");
                }
            }
            outlist.insertOneRow(tmpRowVals);
        }
        // logwdbg("%ld", outlist.tabRowsList.size());
        sqlite3_finalize(stmt);
        return ret;
    }

    int upTabFromCacheDatas(tabCacheValsClass &inlist)
    {
        dbSqlite3NullDect(isNotInit());
        std::string sqlstr;
        int optResult = -1;
        int i;
        sqlite3_stmt *stmt = NULL;
        if(inlist.tabBaseInfo->baseTabName != tabBaseInf.baseTabName || 
            inlist.tabBaseInfo->baseTabColsLen != tabBaseInf.baseTabColsLen)
        {
            logwwrn("%s,%s", inlist.tabBaseInfo->baseTabName.c_str(), tabBaseInf.baseTabName.c_str());
            return -1;
        }
        sqlstr = "replace into " + tabBaseInf.baseTabName + "(";
        for(i = 0; i < inlist.tabBaseInfo->baseTabColsLen; i++)
        {
            if(inlist.tabBaseInfo->baseTabCols[i].name != tabBaseInf.baseTabCols[i].name)
            {
                logwwrn("%s,%s", inlist.tabBaseInfo->baseTabCols[i].name.c_str(), tabBaseInf.baseTabCols[i].name.c_str());
                return -2;
            }
            sqlstr += tabBaseInf.baseTabCols[i].name;
            if(i < tabBaseInf.baseTabColsLen - 1)
            {
                sqlstr += ",";
            }
        }
        sqlstr += ")values(";
        for(i = 0; i < tabBaseInf.baseTabColsLen; i++)
        {
            sqlstr += "?";
            if(i < tabBaseInf.baseTabColsLen - 1)
            {
                sqlstr += ",";
            }
        }
        sqlstr += ");";
        logwdbg("%s", sqlstr.c_str());
        sqlite3BaseOption::exeSqlite3Cmd(*tabBaseInf.baseDbHand, "begin");
        optResult = sqlite3_prepare_v2(*tabBaseInf.baseDbHand, sqlstr.c_str(), -1, &stmt, 0);
        //for(i = 0; i < inlist.tabRowsList.size(); i++)
        foreachCxx(tmpTableInfIter, inlist.tabRowsData)
        {
            sqlite3_reset(stmt);
            if((int)tmpTableInfIter->size() < inlist.tabBaseInfo->baseTabColsLen)
            {
                logwdbg("%d,%d", (int)tmpTableInfIter->size(), inlist.tabBaseInfo->baseTabColsLen);
                optResult = sqlite3OptSqlExeErr;
                break;
            }
            for(i = 0; i < inlist.tabBaseInfo->baseTabColsLen; i++)
            {
                sqlite3_bind_text(stmt, i + 1, (*tmpTableInfIter)[i].c_str(), (*tmpTableInfIter)[i].length(), SQLITE_STATIC);
            }
            optResult = sqlite3_step(stmt);
            if(optResult != SQLITE_OK && optResult != SQLITE_DONE)
            {
                logwdbg("err:%d", optResult);
                optResult = sqlite3OptSqlExeErr;
                break;
            }
        }
        // logwdbg("%d", optResult);
        if(optResult == sqlite3OptSqlExeErr)
        {
            sqlite3BaseOption::exeSqlite3Cmd(*tabBaseInf.baseDbHand, "ROLLBACK");
        }
        else
        {
            //logwdbg(optResult);
            optResult = sqlite3OptOk;
            sqlite3BaseOption::exeSqlite3Cmd(*tabBaseInf.baseDbHand, "commit");
        }
        sqlite3_finalize(stmt);
        return optResult;
    }

    int upTabByJson(Json::Value &jsonRoot) 
    {
        dbSqlite3NullDect(isNotInit());
        tabCacheValsClass tmpInfoVec = tabCacheValsClass(&tabBaseInf);
        tmpInfoVec.jsonToCacheData(jsonRoot);
        return upTabFromCacheDatas(tmpInfoVec);
    }

    int getTabToJson(Json::Value &outRoot, std::string seltStr) 
    {
        dbSqlite3NullDect(isNotInit());
        tabCacheValsClass tmpInfoVec = tabCacheValsClass(&tabBaseInf);
        getTabSelectVals(seltStr, tmpInfoVec);
        return tmpInfoVec.tabValsToJson(outRoot);
    }
    int getTabAllToJson(Json::Value &outRoot)
    {
        std::string seltStr = "select * from " + tabBaseInf.baseTabName + ";";
        return getTabToJson(outRoot, seltStr);
    }
    std::string getTabToJstr(std::string selectStr)
    {
        Json::Value tmpRoot;
        getTabToJson(tmpRoot, selectStr);
        return jsoncppComOptClass::jsonToString(tmpRoot);
    }
    std::string getTabAllToJstr()
    {
        std::string seltStr = "select * from " + tabBaseInf.baseTabName + ";";
        return getTabToJstr(seltStr);
    }
    // sqlite3 **tabBaseInf.baseDbHand = nullptr;
    struct tabStrDefBaseInfo tabBaseInf;
};


typedef void(* parmChangeCallBack)(void *pval);
enum parmTypeEnum
{
	parmTypeInt = 0,
	parmTypeFloat,
	parmTypeString,
	parmTypeMaxNone,
};
enum parmResetLevEnum
{
    parmResetLev0=0,//最低,都能被重置
    parmResetLev1,
    parmResetLev2,
    parmResetLev3,
	parmResetLevMaxNone,
};
struct parmBaseTypeInfo
{
	union
	{
		struct 
		{
			size_t funcIndex:3;
            size_t resetLev:3;
		};
		size_t val;
	};
};
struct parmBaseDataInfo
{
	parmBaseTypeInfo flag;
	const char *name;
	union
	{
		int *valInt;
		float *valFloat;
		string *valStr;
	};
	union
	{
		const int defInt;
		const float defFloat;
		const char *defStr;
	};
	parmChangeCallBack lfunc;//some parameter need run this function when it be changed!
};
// struct parmMngBaseStruct
// {
// 	parmBaseDataInfo *plist;
// 	int plen;//param list len
// };
enum parmOptErrorEnum
{
	parmOptErrorOk = 0,
	parmOptErrNULL,
	parmOptErrJsonParse,
	parmOptErrTypeIndex,
	parmOptErrStrParse,
	parmOptErrNameFind,
	parmOptErrMaxNone
};
//=======================Abandoned, please use pro===============================
#define PARM_COM_DEF_INT(vp, def, lf)		{.flag = {parmTypeInt, 0}, .name = #vp, {.valInt = &vp}, {.defInt = def}, .lfunc = lf}
#define PARM_COM_DEF_FLOAT(vp, def, lf)		{.flag = {parmTypeFloat, 0}, .name = #vp, {.valFloat = &vp}, {.defFloat = def}, .lfunc = lf}
#define PARM_COM_DEF_STR(vp, def, lf)	{.flag = {parmTypeString, 0}, .name = #vp, {.valStr = &vp}, {.defStr = def}, .lfunc = lf}

// #define PARAM_DEFINE_INT_1(pname, vp, def, lf)		{.flag = {parmTypeInt}, .name = pname, {.valInt = &vp}, {.defInt = def}, .lfunc = lf}
// #define PARAM_DEFINE_FLOAT_1(pname, vp, def, lf)		{.flag = {parmTypeFloat}, .name = pname, {.valFloat = &vp}, {.defFloat = def}, .lfunc = lf}
// #define PARAM_DEFINE_STR_1(pname, vp, def, lf)	{.flag = {parmTypeString}, .name = pname, {.valStr = &vp}, {.defStr = def}, .lfunc = lf}

// #define PARAM_DEFINE_INT_2(vname, index, def, lf)   {.flag = {parmTypeInt, 0}, .name = #vname#index, {.valInt = &vname[index]}, {.defInt = def}, .lfunc = lf}
// #define PARAM_DEFINE_FLOAT_2(vname, index, def, lf)    {.flag = {parmTypeFloat, 0}, .name = #vname#index, {.valFloat = &vname[index]}, {.defFloat = def}, .lfunc = lf}
// #define PARAM_DEFINE_STR_2(vname, index, def, lf)	{.flag = {parmTypeString, 0}, .name = #vname#index, {.valStr = &vname[index]}, {.defStr = def}, .lfunc = lf}
//===========================end===================================


#define parmDetectErr() if(plist == NULL || plen <= 0 || strTabOpt.isNotInit())\
    {printferr("");return parmOptErrNULL;}

enum parmTabColsListEnum
{
    parmTabColsPKey=0,
    parmTabColsPVal,
    parmTabColsMax,
};
class parmTabOptClass
{
public:
    static int paramCmpFn(const void *p1, const void*p2)
    {
        parmBaseDataInfo *a1 = (parmBaseDataInfo *)p1, *a2 = (parmBaseDataInfo *)p2;
        return strcmp(a1->name, a2->name);
    }

    static int paramVal2Str(parmBaseDataInfo *pinfo, std::string &outstr)
    {
        if(pinfo == nullptr || pinfo->valInt == nullptr)
        {
            printferr("err");
            return -1;
        }
        if(pinfo->flag.funcIndex == parmTypeInt)
        {
            outstr = to_string(*(pinfo->valInt));
        }
        else if(pinfo->flag.funcIndex == parmTypeFloat)
        {
            outstr = to_string(*(pinfo->valFloat));
        }
        else if(pinfo->flag.funcIndex == parmTypeString)
        {
            outstr = *(pinfo->valStr);
        }
        else
        {
            printferr("%s,%u", pinfo->name, (int)pinfo->flag.funcIndex);
            return -2;
        }
        return 0;
    }

    static int paramStr2Val(parmBaseDataInfo *pinfo, string &instr)
    {
        int valChangeFlag = 0;
        if(pinfo == nullptr || pinfo->valInt == nullptr)
        {
            printferr("err");
            return -1;
        }
        if(pinfo->flag.funcIndex == parmTypeString)
        {
            if(*(pinfo->valStr) != instr)
            {
                *(pinfo->valStr) = instr;
                valChangeFlag = 1;
            }
        }
        else if(pinfo->flag.funcIndex == parmTypeInt)
        {
            int tmpIntVal = atoi(instr.c_str());
            if(*(pinfo->valInt) != tmpIntVal)
            {
               *(pinfo->valInt) = tmpIntVal;
                valChangeFlag = 1;
            }
        }
        else if(pinfo->flag.funcIndex == parmTypeFloat)
        {
            float tmpfVal = atof(instr.c_str());
            if(*(pinfo->valFloat) != tmpfVal)
            {
               *(pinfo->valFloat) = tmpfVal;
                valChangeFlag = 1;
            }
        }
        else
        {
            printferr("%u,%p", (int)pinfo->flag.val, pinfo->valInt);
            return -2;
        }
        if(pinfo->lfunc && valChangeFlag)
        {
            pinfo->lfunc(pinfo);
        }
        return 0;
    }
    parmTabOptClass()
    {
        plist = nullptr;
        plen = 0;
        strTabOpt = strTabOptComClass();
    }
    parmTabOptClass(parmBaseDataInfo *plist, int len, sqlite3 ** dbopt, std::string tabName)
        :plist(plist), plen(len)
    {
        static const struct tabFieldInitInfoDef tabParamFieldInfo[] = 
        {
            {"pkey","NOT NULL UNIQUE",""},
            {"pval","NOT NULL",""}
        }; 
        paramTabInfo.baseDbHand = dbopt;
        paramTabInfo.baseTabName = tabName;
        paramTabInfo.baseTabPrimKey = "primary key(pkey)";
        paramTabInfo.baseTabCols = tabParamFieldInfo;
        paramTabInfo.baseTabColsLen = ARRAY_LEN(tabParamFieldInfo);
        paramTabInfo.baseTabInitCmd = nullptr;
        paramTabInfo.baseTabInitCmdLen = 0;
        strTabOpt.initTable(paramTabInfo);
        sortParm();
        upParmToDefault();
        upParamsFromDb();
        //saveParmToDb();读取失败时有问题。
    }

    int sortParm()
    {
        parmDetectErr();
        qsort(plist, plen, sizeof(parmBaseDataInfo), paramCmpFn);
        return parmOptErrorOk;
    }

    ~parmTabOptClass()
    {

    }

    int upParmToDefault()
    {
        int i, valChangeFlag = 0;
        parmDetectErr();
        for(i = 0; i < plen; i++)
        {
            valChangeFlag = 0;
            if(plist[i].valInt == NULL)
            {
                printferr("%s,%u", plist[i].name, (int)plist[i].flag.funcIndex);
                continue;
            }
            if(plist[i].flag.funcIndex == parmTypeInt)
            {
                if(*(plist[i].valInt) != plist[i].defInt)
                {
                    *(plist[i].valInt) = plist[i].defInt;
                    valChangeFlag = 1;
                }
            }
            else if(plist[i].flag.funcIndex == parmTypeFloat)
            {
                if(*(plist[i].valFloat) != plist[i].defFloat)
                {
                    *(plist[i].valFloat) = plist[i].defFloat;
                    valChangeFlag = 1;
                }
            }
            else if(plist[i].flag.funcIndex == parmTypeString)
            {
                if(*(plist[i].valStr) != plist[i].defStr)
                {
                    *(plist[i].valStr) = plist[i].defStr;
                    valChangeFlag = 1;
                }
            }
            else
            {
                printferr("%s,%u", plist[i].name, (int)plist[i].flag.funcIndex);
                continue;
                //return parmOptErrTypeIndex;
            }
            if(plist[i].lfunc && valChangeFlag)
            {
                plist[i].lfunc(&plist[i]);
            }
        }
        return parmOptErrorOk;
    }

    int resetParmsPro(int resetLevel)
    {
        int i, valChangeFlag = 0;
        parmDetectErr();
        for(i = 0; i < plen; i++)
        {
            valChangeFlag = 0;
            if(plist[i].valInt == NULL)
            {
                printferr("%s,%u", plist[i].name, (int)plist[i].flag.funcIndex);
                continue;
            }
            if(plist[i].flag.resetLev > resetLevel)
            {
                continue;
            }
            if(plist[i].flag.funcIndex == parmTypeInt)
            {
                if(*(plist[i].valInt) != plist[i].defInt)
                {
                    *(plist[i].valInt) = plist[i].defInt;
                    valChangeFlag = 1;
                }
            }
            else if(plist[i].flag.funcIndex == parmTypeFloat)
            {
                if(*(plist[i].valFloat) != plist[i].defFloat)
                {
                    *(plist[i].valFloat) = plist[i].defFloat;
                    valChangeFlag = 1;
                }
            }
            else if(plist[i].flag.funcIndex == parmTypeString)
            {
                if(*(plist[i].valStr) != plist[i].defStr)
                {
                    *(plist[i].valStr) = plist[i].defStr;
                    valChangeFlag = 1;
                }
            }
            else
            {
                printferr("%s,%u", plist[i].name, (int)plist[i].flag.funcIndex);
                continue;
                //return parmOptErrTypeIndex;
            }
            if(plist[i].lfunc && valChangeFlag)
            {
                plist[i].lfunc(&plist[i]);
            }
        }
        saveParmToDb();
        return parmOptErrorOk;
    }

    void upParmFromCacheDatas(tabCacheValsClass &pvals)
    {
        foreachCxx(tmpPval, pvals.tabRowsData)
        {
            setParamByName((*tmpPval)[parmTabColsPKey].c_str(), (*tmpPval)[parmTabColsPVal].c_str());
        }
    }

    int upParamsFromDb()
    {
        parmDetectErr();
        tabCacheValsClass pvalsList;
        string sqlstr = "select * from " + strTabOpt.tabBaseInf.baseTabName + ";";
        strTabOpt.getTabSelectVals(sqlstr, pvalsList);
        upParmFromCacheDatas(pvalsList);
        return parmOptErrorOk;
    }

    int saveParmToDb()
    {
        parmDetectErr();
        tabCacheValsClass pvalsList = tabCacheValsClass(&paramTabInfo);
        for(int i = 0; i < plen; i++)
        {
            if(plist[i].valInt == NULL)
            {
                printferr("%s,%u", plist[i].name, (int)plist[i].flag.funcIndex);
                continue;
            }
            colValsType tmpRowData;
            tmpRowData.push_back(plist[i].name);
            tmpRowData.push_back("");
            if(paramVal2Str(&plist[i], tmpRowData[parmTabColsPVal]) != 0)
            {
                printferr("%s,%u", plist[i].name, (int)plist[i].flag.funcIndex);
                continue;
            }
            pvalsList.insertOneRow(tmpRowData);
        }
        strTabOpt.upTabFromCacheDatas(pvalsList);
        return parmOptErrorOk;
    }

    // int resetParams()
    // {
    //     upParmToDefault();
    //     saveParmToDb();
    //     return parmOptErrorOk;
    // }

    int setParamByName(const char *sname, std::string strval)
    {
        parmDetectErr();
        struct parmBaseDataInfo tmpp = {};// = {.flag.val = 0, .name = sname};
        tmpp.name = sname;
        parmBaseDataInfo *rstp = (parmBaseDataInfo *)bsearch(&tmpp, plist, plen, 
            sizeof(parmBaseDataInfo), paramCmpFn);
        if(rstp == NULL)
        {
            return parmOptErrorOk;
        }
        if(paramStr2Val(rstp, strval))
        {
            printferr("err");
            return parmOptErrTypeIndex;
        }
        return parmOptErrorOk;
    }

    int upParamsByJson(Json::Value &jsonRoot) 
    {
        parmDetectErr();
        tabCacheValsClass parmlist = tabCacheValsClass(&paramTabInfo);
        parmlist.jsonToCacheData(jsonRoot);
        strTabOpt.upTabFromCacheDatas(parmlist);
        upParmFromCacheDatas(parmlist);
        return parmOptErrorOk;
    }

    int upParamsByJsonStr(std::string &jsonStr) 
    {
        parmDetectErr();
        Json::Reader tmpr;
        Json::Value jsonRoot;
        tmpr.parse(jsonStr, jsonRoot);
        return upParamsByJson(jsonRoot);
    }

    int getParamsToJson(Json::Value &outRoot) 
    {
        outRoot.clear();
        parmDetectErr();
        Json::Value &tabVal = outRoot[strTabOpt.tabName()], colsVal;
        colsVal.append("pkey");
        colsVal.append("pval");
        tabVal["cols"] = colsVal;
        Json::Value &rowsVal = tabVal["rows"];
        std::string tmpstr;
        for(int i = 0; i < plen; i++)
        {
            colsVal.clear();
            if(paramVal2Str(&plist[i], tmpstr))
            {
                printferr("err");
                continue;
            }
            colsVal.append(plist[i].name);
            colsVal.append(tmpstr);
            rowsVal.append(colsVal);
        }
        // Json::StyledWriter sw;
        // coutdbg(sw.write(outRoot));
        return parmOptErrorOk;
    }
    int getParamsDbToJson(Json::Value &outRoot) 
    {
        parmDetectErr();
        std::string selStr = "select * from " + strTabOpt.tabName() + ";";
        return strTabOpt.getTabToJson(outRoot, selStr);
    }

    std::string getParamsToJstr()
    {
        Json::Value tmpRoot;
        getParamsToJson(tmpRoot);
        return jsoncppComOptClass::jsonToString(tmpRoot);
    }

private:
	parmBaseDataInfo *plist;
	int plen;//param list len
    strTabOptComClass strTabOpt;
    struct tabStrDefBaseInfo paramTabInfo;
};
#endif

测试代码:

#include <types.h>
#include <ctimer.h>
#include <json/json.h>
#include <base64Java.h>
#include <zlib.h>
#include <logBaseWork.h>
#include <hexbufToStr.h>
#include <mosquittopp.h>
#include <baseProt.h>
#include <miscOperate.h>
#include <openssl/md5.h>
#include <sqlTabOptCom.h>
#include <mongoose.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> 
#include <sql3ComOptPro.h>

struct dbFileInformDef projDbInfoBuf[] =
{
    {NULL, "./projParm.db", "./projParm-bk.db"},
    {NULL, "./projRecord.db", "./projRecord-bk.db"},
};


static const struct tabFieldInitInfoDef infoProjRecords[]=
{
    {"time","",""},{"type","",""},{"addr","",""},{"count","",""},
    {"extend0","","",},{"extend1","",""},{"explain","",""},{"upflag","","0"},
};
const std::string tabExtProjRecord[] = 
{
    // "CREATE INDEX index_extend0 on record (extend0);",
    // "update record set online = \"0\";",
    "ALTER TABLE 'record' ADD COLUMN upflag TEXT DEFAULT('0');",
};
const struct tabStrDefBaseInfo tabBaseProjRecords = 
{
    "record", "primary key(time, type, addr, count) ", infoProjRecords, ARRAY_LEN(infoProjRecords), 
    tabExtProjRecord, ARRAY_LEN(tabExtProjRecord), &projDbInfoBuf[1].dbSqlOpt
};

strTabOptComClass tabProjRec;

void initProjRecordTab()
{
    tabProjRec = strTabOptComClass(tabBaseProjRecords);
}

void inputProjRecord(std::string itype, std::string iaddr, std::string icount, std::string iext0, std::string iext1, std::string exp)
{
    u64 tmptime = timerc::getTimeNowUs();
    tabCacheValsClass tmplist = tabCacheValsClass(&tabProjRec.tabBaseInf);
    colValsType tmpRowData;
    tmpRowData.push_back(to_string(tmptime));
    tmpRowData.push_back(itype);
    tmpRowData.push_back(iaddr);
    tmpRowData.push_back(icount);
    tmpRowData.push_back(iext0);
    tmpRowData.push_back(iext1);
    tmpRowData.push_back(exp);
    tmpRowData.push_back("0");
    tmplist.insertOneRow(tmpRowData);
    tabProjRec.upTabFromCacheDatas(tmplist);
}


int normInt1;
float normFloat1;
std::string normStr1;
int normInt2[5];
float normFloat2[5];
std::string normStr2[5];
struct parmBaseDataInfo parmNormalList[] = 
{
    PARM_COM_DEF_INT(normInt1, 0, NULL),
    PARM_COM_DEF_FLOAT(normFloat1, 0, NULL),
    PARM_COM_DEF_STR(normStr1, "MY_DEFAULT_STR", NULL),
    PARM_COM_DEF_INT(normInt2[0], 0, NULL),
    PARM_COM_DEF_INT(normInt2[1], 0, NULL),
    PARM_COM_DEF_INT(normInt2[2], 0, NULL),
    PARM_COM_DEF_INT(normInt2[3], 0, NULL),
    PARM_COM_DEF_INT(normInt2[4], 0, NULL),
    PARM_COM_DEF_FLOAT(normFloat2[0], 0, NULL),
    PARM_COM_DEF_FLOAT(normFloat2[1], 0, NULL),
    PARM_COM_DEF_FLOAT(normFloat2[2], 0, NULL),
    PARM_COM_DEF_FLOAT(normFloat2[3], 0, NULL),
    PARM_COM_DEF_FLOAT(normFloat2[4], 0, NULL),
    PARM_COM_DEF_STR(normStr2[0], "", NULL),
    PARM_COM_DEF_STR(normStr2[1], "", NULL),
    PARM_COM_DEF_STR(normStr2[2], "", NULL),
    PARM_COM_DEF_STR(normStr2[3], "", NULL),
    PARM_COM_DEF_STR(normStr2[4], "", NULL),
};


std::string projVersion;
std::string projSerial;
struct parmBaseDataInfo parmFixedList[] = 
{
    PARM_COM_DEF_INT(DEBUG_LEVEL_DEF, 4, NULL),
    PARM_COM_DEF_INT(logSelectFlag, 0, NULL),
    PARM_COM_DEF_STR(projVersion, "PROJ_VER_DEFAULT", NULL),
    PARM_COM_DEF_STR(projSerial, "PROJ_SER_DEFAULT", NULL),
};

parmTabOptClass testParmNormal;
parmTabOptClass testParmFixed;

int main(int argc,char *argv[])
{
    sqlite3BaseOption::tabDbListsInitPro(projDbInfoBuf, ARRAY_LEN(projDbInfoBuf));
    testParmNormal = parmTabOptClass(parmNormalList, ARRAY_LEN(parmNormalList), &projDbInfoBuf[0].dbSqlOpt, "parmNormal");
    testParmFixed = parmTabOptClass(parmFixedList, ARRAY_LEN(parmFixedList), &projDbInfoBuf[0].dbSqlOpt, "parmFixed");
    initProjRecordTab(); 
    inputProjRecord("1", "2", "3", "4", "5", "6");
    std::string tmpstr = "select * from " + tabProjRec.tabName() + ";";
    logwdbg("%s", tabProjRec.getTabAllToJstr().substr(0, 1000).c_str());
    normInt2[1] = 5;
    normFloat2[2] = 6.9;
    normStr2[3] = "23";
    normFloat1 = -1.23;
    testParmNormal.saveParmToDb();
    logwdbg("%s", testParmNormal.getParamsToJstr().substr(0, 1000).c_str());
    tmpstr = MiscOperateClass::readFileStr("mytest.txt");
    logwdbg("%s", tmpstr.c_str());
    testParmNormal.upParamsByJsonStr(tmpstr);
    logwdbg("%f", normFloat1);
    sqlite3BaseOption::tabDbListsQuit(projDbInfoBuf, ARRAY_LEN(projDbInfoBuf));
	return 0;
}

使用外键:

参考:

sqlite3 外键的使用 - 简书

1.打开外键功能
        std::string sqlstr = "PRAGMA foreign_keys = ON";
        return exeSql3Str(sqldbopt, sqlstr);
2.开启外键。这里吧TabDevPort的DevId设置为TabTaskReg的DevId的外键。TabTaskReg在ON DELETE删除和ON UPDATE时会更新TabDevPort的DevId。而跟新TabDevPort的DevId会报错!
create table if not exists TabDevPort (DevId TEXT NOT NULL,DevPort TEXT,portName TEXT,portDir TEXT,portPwd TEXT,portOpenTime TEXT,primary key(DevId, DevPort),FOREIGN KEY (DevId) REFERENCES TabTaskReg(DevId) ON DELETE CASCADE ON UPDATE CASCADE);
说明:
1.修改删除外键主表的TabTaskReg的外键可以更新字表的外键DevId
2.update insert replace子表添加或修改主表不存在的外键,会出错!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值