SQLite is an in-process library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine. The code for SQLite is in the public domain and is thus free for use for any purpose, commercial or private. SQLite is the most widely deployed database in the world with more applications than we can count, including several high-profile projects.
http://www.sqlite.org/
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。
由于使C API, 有很多优秀的对SQLITE进行的封装,今天就介绍两种 easySQLite和cppSQLite。
为什么easySQLite优于其他封装?
(https://code.google.com/archive/p/easysqlite/ 哈哈,不敢苟同,反正挺好用的)
elegant, objective solution (优雅的面向对象解决方案)
explicit naming and calling (显式命名和调用)
uses exceptions or methods return values (使用异常以及方法返回值)
clear, understandable usage (容易理解)
flexible and expandable (灵活而且可扩展)
strongly tested (tests included) (经过强测试)
这里就简单展示几个而已:
SqlCommon.h
//
// Copyright (C) 2010 Piotr Zagawa
//
// Released under BSD License
//
#pragma once
#include
#include
#include
#include
namespace sql
{
//field state enums
//--------------------------
enum field_use
{
FIELD_DEFAULT,
FIELD_KEY,
DEFINITION_END,
};
enum field_type
{
type_undefined,
type_int,
type_text,
type_float,
type_bool,
type_time,
};
enum field_flags
{
flag_none = 0,
flag_not_null = 1,
flag_primary_key = 2,
};
//common data types
//--------------------------
//string
typedef std::string string;
//integer
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 integer;
#else
typedef long long int integer;
#endif
//time
class time
{
private:
time_t _value;
private:
string format(const char* format);
public:
time();
time(const time& value);
time(integer value);
time& operator=(const time& value);
bool operator==(const time& value);
static time now();
public:
double diff(time& value);
time_t get();
void addValue(integer value);
void addMinutes(integer count);
void addHours(integer count);
void addDays(integer count);
public:
integer asInteger();
string asString();
string asTimeString();
string asDateString();
};
//common exception class
class Exception
{
private:
string _msg;
public:
Exception(string msg)
: _msg(msg)
{
};
string msg()
{
return _msg;
}
};
//comment this directive to disable exceptions
//#define USE_EXCEPTIONS
#ifndef THROW_EXCEPTION
#ifdef USE_EXCEPTIONS
#define THROW_EXCEPTION(msg) throw Exception(msg);
#else
#define THROW_EXCEPTION(msg)
#endif
#endif
//utils
//--------------------------
class log
{
public:
log(std::string s)
{
std::string text = s;
text += "\r\n";
printf("%s",text.c_str());
}
};
string intToStr(int value);
string intToStr(integer value);
string quoteStr(string value);
string binToHex(const char* buffer, int size);
string generateSHA(string& value);
string& trimleft(string& s);
string& trimright(string& s);
string& trim(string& s);
string trim(const string& s);
void listToVector(string s, std::vector<string>& vector, const char* sep = ",");
//sql eof
};
用Field 对象定义一个表结构
SqlField.h
#pragma once
#include "SqlCommon.h"
namespace sql
{
class Field
{
public:
friend class FieldSet;
private:
string _name;
field_use _use;
field_type _type;
int _index;
int _flags;
public:
Field(field_use use);
Field(string name, field_type type, int flags = flag_none);
Field(const Field& value);
public:
bool isKeyIdField();
bool isEndingField();
public:
int getIndex();
string getName() const;
string getTypeStr();
field_type getType();
bool isPrimaryKey();
bool isNotNull();
public:
string getDefinition();
static Field* createFromDefinition(string value);
};
//sql eof
};
先定义一个Database对象,然后打开进行操作
SqlDatabase.h
//
// Copyright (C) 2010 Piotr Zagawa
//
// Released under BSD License
//
#pragma once
#include "sqlite3.h"
#include "SqlCommon.h"
namespace sql
{
class Database
{
private:
sqlite3* _db;
string _err_msg;
int _result_open;
public:
Database(void);
~Database(void);
public:
sqlite3* getHandle();
string errMsg();
bool open(string filename);
void close();
bool isOpen();
public:
bool transactionBegin();
bool transactionCommit();
bool transactionRollback();
};
//sql eof
};
通过Table对象来操作数据库了
SqlTable.h
//
// Copyright (C) 2010 Piotr Zagawa
//
// Released under BSD License
//
#pragma once
#include "sqlite3.h"
#include "SqlCommon.h"
#include "SqlFieldSet.h"
#include "SqlRecordSet.h"
namespace sql
{
class Table
{
private:
sqlite3* _db;
string _tableName;
RecordSet _recordset;
public:
Table(sqlite3* db, string tableName, Field* definition);
Table(sqlite3* db, string tableName, FieldSet* fields);
public:
string name();
string getDefinition();
string toString();
string errMsg();
FieldSet* fields();
sqlite3* getHandle();
public:
bool create();
bool exists();
bool remove();
bool truncate();
public:
bool open();
bool open(string whereCondition);
bool open(string whereCondition, string sortBy);
bool query(string queryStr);
int totalRecordCount();
public:
int recordCount();
Record* getRecord(int record_index);
Record* getTopRecord();
Record* getRecordByKeyId(integer keyId);
public:
bool addRecord(Record* record);
bool updateRecord(Record* record);
bool deleteRecords(string whereCondition);
bool copyRecords(Table& source);
bool backup(Table& source);
public:
static Table* createFromDefinition(sqlite3* db, string tableName, string fieldsDefinition);
};
如果要修改/添加/删除数据,您可以使用Record对象来完成
SqlRecord.h
//
// Copyright (C) 2010 Piotr Zagawa
//
// Released under BSD License
//
#pragma once
#include
#include "SqlCommon.h"
#include "SqlValue.h"
#include "SqlFieldSet.h"
namespace sql
{
class Record
{
private:
FieldSet* _fields;
std::vector _values;
public:
Record(FieldSet* fields);
Record(Record* record);
Record(const Record& record);
private:
friend class RecordSet;
void initColumnCount(int columns);
void initColumnValue(int column_index, char* value, field_type type);
public:
int columnCount();
Value* getValue(int column_index);
Value* getValue(string fieldName);
Value* getValue(const Field& field);
Value* getKeyIdValue();
Field* fieldByName(string fieldName);
FieldSet* fields();
string toString();
string toSql();
bool equalsColumnValue(Record* record, string fieldName);
bool equalsValues(Record* record);
public:
string toSqlInsert(string tableName);
string toSqlUpdate(string tableName);
public:
void setNull(int index);
void setString(int index, string value);
void setInteger(int index, integer value);
void setDouble(int index, double value);
void setBool(int index, bool value);
void setTime(int index, time value);
public:
void setNull(string fieldName);
void setString(string fieldName, string value);
void setInteger(string fieldName, integer value);
void setDouble(string fieldName, double value);
void setBool(string fieldName, bool value);
void setTime(string fieldName, time value);
public:
void setNull(Field& field);
void setString(Field& field, string value);
void setInteger(Field& field, integer value);
void setDouble(Field& field, double value);
void setBool(Field& field, bool value);
void setTime(Field& field, time value);
};
//sql eof
};
应用:
//define table structure
Field definition_tbPerson[] =
{
Field(FIELD_KEY),
Field("fname", type_text, flag_not_null),
Field("lname", type_text, flag_not_null),
Field("birthdate", type_time),
Field(DEFINITION_END),
};
//define database object
sql::Database db;
try
{
//open database file
db.open("test.db");
//define table object
Table tbPerson(db.getHandle(), "person", definition_tbPerson);
//remove table from database if exists
if (tbPerson.exists())
tbPerson.remove();
//create new table
tbPerson.create();
//define new record
Record record(tbPerson.fields());
//set record data
record.setString("fname", "Jan");
record.setString("lname", "Kowalski");
record.setTime("birthdate", time::now());
//add 10 records
for (int index = 0; index < 10; index++)
tbPerson.addRecord(&record);
//select record to update
if (Record* record = tbPerson.getRecordByKeyId(7))
{
record->setString("fname", "Frank");
record->setString("lname", "Sinatra");
record->setNull("birthdate");
tbPerson.updateRecord(record);
}
//load all records
tbPerson.open();
//list loaded records
for (int index = 0; index < tbPerson.recordCount(); index++)
if (Record* record = tbPerson.getRecord(index))
sql::log(record->toString());
sql::log("");
sql::log("ALL OK");
} catch (Exception e) {
printf("ERROR: %s\r\n", e.msg().c_str());
}
http://www.codeproject.com/Articles/6343/CppSQLite-C-Wrapper-for-SQLite
CppSQLite3.h
///////////////////////////////////////////////////////////////////////////////
// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
//
#ifndef _CppSQLite3_H_
#define _CppSQLite3_H_
#include "sqlite3.h"
#include
#include
#define CPPSQLITE_ERROR 1000
class CppSQLite3Exception
{
public:
CppSQLite3Exception(const int nErrCode,
char* szErrMess,
bool bDeleteMsg=true);
CppSQLite3Exception(const CppSQLite3Exception& e);
virtual ~CppSQLite3Exception();
const int errorCode() { return mnErrCode; }
const char* errorMessage() { return mpszErrMess; }
static const char* errorCodeAsString(int nErrCode);
private:
int mnErrCode;
char* mpszErrMess;
};
class CppSQLite3Buffer
{
public:
CppSQLite3Buffer();
~CppSQLite3Buffer();
const char* format(const char* szFormat, ...);
operator const char*() { return mpBuf; }
void clear();
private:
char* mpBuf;
};
class CppSQLite3Binary
{
public:
CppSQLite3Binary();
~CppSQLite3Binary();
void setBinary(const unsigned char* pBuf, int nLen);
void setEncoded(const unsigned char* pBuf);
const unsigned char* getEncoded();
const unsigned char* getBinary();
int getBinaryLength();
unsigned char* allocBuffer(int nLen);
void clear();
private:
unsigned char* mpBuf;
int mnBinaryLen;
int mnBufferLen;
int mnEncodedLen;
bool mbEncoded;
};
class CppSQLite3Query
{
public:
CppSQLite3Query();
CppSQLite3Query(const CppSQLite3Query& rQuery);
CppSQLite3Query(sqlite3* pDB,
sqlite3_stmt* pVM,
bool bEof,
bool bOwnVM=true);
CppSQLite3Query& operator=(const CppSQLite3Query& rQuery);
virtual ~CppSQLite3Query();
int numFields();
int fieldIndex(const char* szField);
const char* fieldName(int nCol);
const char* fieldDeclType(int nCol);
int fieldDataType(int nCol);
const char* fieldValue(int nField);
const char* fieldValue(const char* szField);
int getIntField(int nField, int nNullValue=0);
int getIntField(const char* szField, int nNullValue=0);
sqlite_int64 getInt64Field(int nField, sqlite_int64 nNullValue=0);
sqlite_int64 getInt64Field(const char* szField, sqlite_int64 nNullValue=0);
double getFloatField(int nField, double fNullValue=0.0);
double getFloatField(const char* szField, double fNullValue=0.0);
const char* getStringField(int nField, const char* szNullValue="");
const char* getStringField(const char* szField, const char* szNullValue="");
const unsigned char* getBlobField(int nField, int& nLen);
const unsigned char* getBlobField(const char* szField, int& nLen);
bool fieldIsNull(int nField);
bool fieldIsNull(const char* szField);
bool eof();
void nextRow();
void finalize();
private:
void checkVM();
sqlite3* mpDB;
sqlite3_stmt* mpVM;
bool mbEof;
int mnCols;
bool mbOwnVM;
};
class CppSQLite3Table
{
public:
CppSQLite3Table();
CppSQLite3Table(const CppSQLite3Table& rTable);
CppSQLite3Table(char** paszResults, int nRows, int nCols);
virtual ~CppSQLite3Table();
CppSQLite3Table& operator=(const CppSQLite3Table& rTable);
int numFields();
int numRows();
const char* fieldName(int nCol);
const char* fieldValue(int nField);
const char* fieldValue(const char* szField);
int getIntField(int nField, int nNullValue=0);
int getIntField(const char* szField, int nNullValue=0);
double getFloatField(int nField, double fNullValue=0.0);
double getFloatField(const char* szField, double fNullValue=0.0);
const char* getStringField(int nField, const char* szNullValue="");
const char* getStringField(const char* szField, const char* szNullValue="");
bool fieldIsNull(int nField);
bool fieldIsNull(const char* szField);
void setRow(int nRow);
void finalize();
private:
void checkResults();
int mnCols;
int mnRows;
int mnCurrentRow;
char** mpaszResults;
};
class CppSQLite3Statement
{
public:
CppSQLite3Statement();
CppSQLite3Statement(const CppSQLite3Statement& rStatement);
CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM);
virtual ~CppSQLite3Statement();
CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);
int execDML();
CppSQLite3Query execQuery();
void bind(int nParam, const char* szValue);
void bind(int nParam, const int nValue);
void bind(int nParam, const double dwValue);
void bind(int nParam, const unsigned char* blobValue, int nLen);
void bindNull(int nParam);
int bindParameterIndex(const char* szParam);
void bind(const char* szParam, const char* szValue);
void bind(const char* szParam, const int nValue);
void bind(const char* szParam, const double dwValue);
void bind(const char* szParam, const unsigned char* blobValue, int nLen);
void bindNull(const char* szParam);
void reset();
void finalize();
private:
void checkDB();
void checkVM();
sqlite3* mpDB;
sqlite3_stmt* mpVM;
};
class CppSQLite3DB
{
public:
CppSQLite3DB();
virtual ~CppSQLite3DB();
void open(const char* szFile);
void close();
bool tableExists(const char* szTable);
int execDML(const char* szSQL);
CppSQLite3Query execQuery(const char* szSQL);
int execScalar(const char* szSQL, int nNullValue=0);
CppSQLite3Table getTable(const char* szSQL);
CppSQLite3Statement compileStatement(const char* szSQL);
sqlite_int64 lastRowId();
void interrupt() { sqlite3_interrupt(mpDB); }
void setBusyTimeout(int nMillisecs);
static const char* SQLiteVersion() { return SQLITE_VERSION; }
static const char* SQLiteHeaderVersion() { return SQLITE_VERSION; }
static const char* SQLiteLibraryVersion() { return sqlite3_libversion(); }
static int SQLiteLibraryVersionNumber() { return sqlite3_libversion_number(); }
bool IsAutoCommitOn();
private:
CppSQLite3DB(const CppSQLite3DB& db);
CppSQLite3DB& operator=(const CppSQLite3DB& db);
sqlite3_stmt* compile(const char* szSQL);
void checkDB();
sqlite3* mpDB;
int mnBusyTimeoutMs;
};
#endif
应用:
#include "CppSQLite.h"
#include
#include
using namespace std;
const char* gszFile = "C:\\test.db";
int main(int argc, char** argv)
{
try
{
int i, fld;
time_t tmStart, tmEnd;
CppSQLiteDB db;
cout << "SQLite Version: " << db.SQLiteVersion() << endl;
remove(gszFile);
db.open(gszFile);
cout << endl << "Creating emp table" << endl;
db.execDML("create table emp(empno int, empname char(20));");
///////////////////////////////////////////////////////////////
// Execute some DML, and print number of rows affected by each one
///////////////////////////////////////////////////////////////
cout << endl << "DML tests" << endl;
int nRows = db.execDML("insert into emp values (7, 'David Beckham');");
cout << nRows << " rows inserted" << endl;
nRows = db.execDML(
"update emp set empname = 'Christiano Ronaldo' where empno = 7;");
cout << nRows << " rows updated" << endl;
nRows = db.execDML("delete from emp where empno = 7;");
cout << nRows << " rows deleted" << endl;
/////////////////////////////////////////////////////////////////
// Transaction Demo
// The transaction could just as easily have been rolled back
/////////////////////////////////////////////////////////////////
int nRowsToCreate(50000);
cout << endl << "Transaction test, creating " << nRowsToCreate;
cout << " rows please wait..." << endl;
tmStart = time(0);
db.execDML("begin transaction;");
for (i = 0; i < nRowsToCreate; i++)
{
char buf[128];
sprintf(buf, "insert into emp values (%d, 'Empname%06d');", i, i);
db.execDML(buf);
}
db.execDML("commit transaction;");
tmEnd = time(0);
////////////////////////////////////////////////////////////////
// Demonstrate CppSQLiteDB::execScalar()
////////////////////////////////////////////////////////////////
cout << db.execScalar("select count(*) from emp;")
<< " rows in emp table in ";
cout << tmEnd-tmStart << " seconds (that was fast!)" << endl;
////////////////////////////////////////////////////////////////
// Re-create emp table with auto-increment field
////////////////////////////////////////////////////////////////
cout << endl << "Auto increment test" << endl;
db.execDML("drop table emp;");
db.execDML(
"create table emp(empno integer primary key, empname char(20));");
cout << nRows << " rows deleted" << endl;
for (i = 0; i < 5; i++)
{
char buf[128];
sprintf(buf,
"insert into emp (empname) values ('Empname%06d');", i+1);
db.execDML(buf);
cout << " primary key: " << db.lastRowId() << endl;
}
///////////////////////////////////////////////////////////////////
// Query data and also show results of inserts into auto-increment field
//////////////////////////////////////////////////////////////////
cout << endl << "Select statement test" << endl;
CppSQLiteQuery q = db.execQuery("select * from emp order by 1;");
for (fld = 0; fld < q.numFields(); fld++)
{
cout << q.fieldName(fld) << "(" << q.fieldType(fld) << ")|";
}
cout << endl;
while (!q.eof())
{
cout << q.fieldValue(0) << "|";
cout << q.fieldValue(1) << "|" << endl;
q.nextRow();
}
///////////////////////////////////////////////////////////////
// SQLite's printf() functionality. Handles embedded quotes and NULLs
////////////////////////////////////////////////////////////////
cout << endl << "SQLite sprintf test" << endl;
CppSQLiteBuffer bufSQL;
bufSQL.format("insert into emp (empname) values (%Q);", "He's bad");
cout << (const char*)bufSQL << endl;
db.execDML(bufSQL);
bufSQL.format("insert into emp (empname) values (%Q);", NULL);
cout << (const char*)bufSQL << endl;
db.execDML(bufSQL);
////////////////////////////////////////////////////////////////////
// Fetch table at once, and also show how to
// use CppSQLiteTable::setRow() method
//////////////////////////////////////////////////////////////////
cout << endl << "getTable() test" << endl;
CppSQLiteTable t = db.getTable("select * from emp order by 1;");
for (fld = 0; fld < t.numFields(); fld++)
{
cout << t.fieldName(fld) << "|";
}
cout << endl;
for (int row = 0; row < t.numRows(); row++)
{
t.setRow(row);
for (int fld = 0; fld < t.numFields(); fld++)
{
if (!t.fieldIsNull(fld))
cout << t.fieldValue(fld) << "|";
else
cout << "NULL" << "|";
}
cout << endl;
}
////////////////////////////////////////////////////////////////////
// Test CppSQLiteBinary by storing/retrieving some binary data, checking
// it afterwards to make sure it is the same
//////////////////////////////////////////////////////////////////
cout << endl << "Binary data test" << endl;
db.execDML("create table bindata(desc char(10), data blob);");
unsigned char bin[256];
CppSQLiteBinary blob;
for (i = 0; i < sizeof bin; i++)
{
bin[i] = i;
}
blob.setBinary(bin, sizeof bin);
bufSQL.format("insert into bindata values ('testing', %Q);",
blob.getEncoded());
db.execDML(bufSQL);
cout << "Stored binary Length: " << sizeof bin << endl;
q = db.execQuery("select data from bindata where desc = 'testing';");
if (!q.eof())
{
blob.setEncoded((unsigned char*)q.fieldValue("data"));
cout << "Retrieved binary Length: "
<< blob.getBinaryLength() << endl;
}
const unsigned char* pbin = blob.getBinary();
for (i = 0; i < sizeof bin; i++)
{
if (pbin[i] != i)
{
cout << "Problem: i: ," << i << " bin[i]: "
<< pbin[i] << endl;
}
}
/////////////////////////////////////////////////////////
// Pre-compiled Statements Demo
/////////////////////////////////////////////////////////////
cout << endl << "Transaction test, creating " << nRowsToCreate;
cout << " rows please wait..." << endl;
db.execDML("drop table emp;");
db.execDML("create table emp(empno int, empname char(20));");
tmStart = time(0);
db.execDML("begin transaction;");
CppSQLiteStatement stmt = db.compileStatement(
"insert into emp values (?, ?);");
for (i = 0; i < nRowsToCreate; i++)
{
char buf[16];
sprintf(buf, "EmpName%06d", i);
stmt.bind(1, i);
stmt.bind(2, buf);
stmt.execDML();
stmt.reset();
}
db.execDML("commit transaction;");
tmEnd = time(0);
cout << db.execScalar("select count(*) from emp;")
<< " rows in emp table in ";
cout << tmEnd-tmStart << " seconds (that was even faster!)" << endl;
cout << endl << "End of tests" << endl;
}
catch (CppSQLiteException& e)
{
cerr << e.errorCode() << ":" << e.errorMessage() << endl;
}
////////////////////////////////////////////////////////////////
// Loop until user enters q or Q
///////////////////////////////////////////////////////////
char c(' ');
while (c != 'q' && c != 'Q')
{
cout << "Press q then enter to quit: ";
cin >> c;
}
return 0;
}