SQLite 注意事项

SQLite 常见问题

原文地址

  1. 在创建一个数据库表时,使用 integer primary key 声明一个字段为主键,此后,向该表插入数据时,如果不指定该字段的值(即 NULL),那么该值则自动设置为该表中所有数据中最大的值增一,如果最大值 9223372036854775807 已经被使用,那么则随机选择一个未使用的值插入。另外,因为数据可能会被删除,所以如果想要数据库表在生命周期内的主键始终是唯一的,可以使用 autoincrement 关键字来修饰主键字段。这样,插入的主键值始终是递增的,但是,若已经递增到最大值后再插入数据,则会报 SQLITE_FULL 错误。

  2. SQLite 支持整型(integer)、浮点型(real)、字符串(text)、二进制数据块(blob)以及空(null)等类型数据的存储,虽然在创建表时指明了每个字段的类型,但是在实际插入数据时,并没有严格的限制,每个字段都可以存储任意长度的字符串。但是,对于使用 integer primary key 修饰的字段则例外,对其插入任何非整型的值都会导致错误。

  3. SQLite 通过读写锁来控制数据库的访问,其支持不同的进程同时查询数据库,但是不支持多进程修改数据库,并且在 NFS 文件系统中,读写锁未必能够正确生效。如果 SQLite 访问一个被其他进程上锁的数据库,默认返回一个 SQLITE_BUSY 状态,但是可以通过 sqlite3_busy_handler()sqlite3_busy_timeout() 函数来修改默认操作。

  4. 在使用命令行操作数据库时,可以通过 .tables.schema 命令来查看数据库中有多少表或索引,而这些表的信息则存储在一个特殊的只读表 SQLITE_MASTER 中,使用 .schema sqlite_master 命令可以得到如下结果:

    CREATE TABLE sqlite_master (
      type text,
      name text,
      tbl_name text,
      rootpage integer,
      sql text
    );
    

    所以在程序接口中,可以通过查询该表来获取数据库中表的信息。

    select name from sqlite_master where type='table' order by name;
    

    注意不能自己更新该表,其是在创建表、索引或销毁表、索引时,自动更新的。
    另外,临时表、索引及触发器在另一个 sqlite_temp_master 表中,该表和 sqlite_master 表的结构是一样的。

  5. 在 SQLite 中,表结构的修改被限制了,如删除表中的一个字段,则需要重新创建一个表,如下:

    BEGIN TRANSACTION;
    CREATE TEMPORARY TABLE t1_backup(a,b);
    INSERT INTO t1_backup SELECT a,b FROM t1;
    DROP TABLE t1;
    CREATE TABLE t1(a,b);
    INSERT INTO t1 SELECT a,b FROM t1_backup;
    DROP TABLE t1_backup;
    COMMIT;
    
  6. 在 SQLite 中,删除数据后,空出的存储空间并不会直接归还给操作系统,而是被保留以备重用。如果删除了很多数据,可以使用 VACUUM 命令,该命令会重构数据库,归还持有的空闲空间,使数据库文件占用最小的空间。但是这个过程会消耗时间,并临时占用最高是原数据库文件大小 2 倍的存储空间。

  7. 在 SQLite 中向表中插入数据时,如果字符串中包含有引号,那么需要注意,如果该引号同包裹整个字符串的引号相同,则需要两个连续的引号来表示其为需要插入的字符引号,如下:

    insert into table1 values ('a',"a","'b'",'"b"','''c''',"""c""",);
    

    那么实际插入的数据为:(a,a,'b',"b",'c',"c")

  8. 当 SQL 语句发生变动而无法执行时,会返回 SQLITE_SCHEMA 错误,此时,需要使用 sqlite3_prepare() 函数对 SQL 语句重新编译。而该错误只有在使用 sqlite3_prepare()sqlite3_step() 接口执行 SQL 语句时返回,而不是在使用 sqlite3_exec() 函数时返回。鉴于此,推荐使用 sqlite3_prepare_v2() 函数,该函数会在 SQL 语句发生变动时,自动重新编译 SQL 语句,而不会返回 SQLITE_SCHEMA 错误。

  9. 在 SQLite 中 ROUND(9.95,1) 返回值为 9.9 而不是 10.0 ,这是因为 SQLite 中的计算是基于二进制的,而 0.95 同大多有限长度的十进制浮点数一样是无法转换为有限长度的二进制数的,最接近的数为 9.94999999… 所以最终约等于 9.9 而不是 10.0 。

  10. 在 SQLite 中,仅仅是 ASCII 中的字符不区分大小写,其他字符并不支持。

  11. 数据库插入数据的操作受到硬盘读写速度的限制,对于一个数据库操作而言,只有等到数据完全同步到硬盘上,整个操作才算完毕,所以这很耗时,但也是安全的。但是有别的选择,使用 PRAGMA synchronous=OFF 关闭安全同步,那么数据操作将会快得多,但是一旦发生断电或其他故障,那么数据库文件可能会损坏。

  12. 在删除数据时,如果没有使用 SQLITE_SECURE_DELETE 选项将所有删除的内容置为 0 ,并且没有执行过 VACUUM 命令,那么删除的内容可能还在数据库文件中,只是所在空间被标记为重用而已,也许还能找回。

  13. 在使用条件语句查询某一列时,应使用单引号包裹条件值,因为使用双引号时,如果条件值同列名相同,那么所有结果都会返回,如下:

    select * from info where name="name"
    select * from info where name='name'
    

    这两种写法的输出结果是不同的,第一个等同于 select * from info where name=name ,所以所有的结果都返回,而第二种写法才能找出符合条件的数据。

猜你喜欢

转载自blog.csdn.net/u011374318/article/details/89945684
今日推荐