关于女神SQLite的疑惑(2)


还是女神SQLite的话题,继续讨论有关她的种种常见疑惑。

1. 问:女神SQLite是线程安全的吗?

1. 答:SQLite是线程安全的,这点确凿无疑。但我要补充的一句话是:线程有时候是恶魔,不要让女神轻易接近他!

说线程是恶魔可能有点危言耸听的味道,难道线程不是我们广大编程群众喜闻乐见的基本工具么?都用了多少年啦没啥问题!的确如此,但世界上总有头上长角的牛人,可以在早已被认为平平无奇的地方硬生生找出普通人发现不了的深层逻辑谬误,并且能装订成册警示后人,来膜拜下:

www2.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.pdf

言归正传,SQLite本身是线程安全的,但要获得这个技能,你必须在编译的时候定义宏 SQLITE_THREADSAFE 为1。如果你不确定即将链接到你程序的 SQLite 库文件是否拥有了线程安全技能,你可以调用以下函数来确认。

sqlite3_threadsafe()

SQLite 使用互斥锁来确保多线程可以顺序地访问普通数据结构,从而确保安全性。然而,频繁地索取和释放这些互斥锁势必会轻微地降低 SQLite的性能。因此,如果你不需要 SQLite 为你提供线程安全的保障,你可以用下面的编译选项来关闭它们以获得最高性能

-DSQLITE_THREADSAFE=0

另外要额外提醒一句,在 Unix/Linux 系统下,不要将一个打开的 SQLite 数据库连接,通过调用 fork() 函数传递到子进程去使用,谨记。

2. 问:怎么列出一个数据库中所有的表和索引?

2. 答:这分两种情况,① 使用SQLite命令行的时候;② 使用C/C++编程API的时候。

第一种情况,你直接使用SQLite的内置命令 ".tables" 即可查看当前数据库中的所有表,或者使用内置命令 ".schema" 来查看当前数据库中所有的表和索引的创建语句。

第二种情况,可以在一个特殊的表 "SQLITE_MASTER" 获得所有的的表和索引。每一个SQLite数据库都有一个称为 SQLITE_MASTER 的表,它统管了数据库中所有其他的元素,它的内部定义如下:

CREATE TABLE sqlite_master (

  type TEXT,

  name TEXT,

  tbl_name TEXT,

  rootpage INTEGER,

  sql TEXT

);

对于一个表来说, type 域就是 'table' ,name 域就是表的名字。因此可以使用以下 SQL 语句来查询当前数据库库中所有的表:

SELECT name FROM sqlite_master

WHERE type='table';

对于一个索引来说,type 域就是 'index'name 域就是索引的名字,而 tbl_name 域则表示该索引所在的表的名字。

对于表和索引,sql 域都是创建他们的原始 SQL 语句。对于自动创建的索引(比如自动递增的主键)而言,该域为 NULL。

表 SQLITE_MASTER 是只读的,你无法对其进行诸如 UPDATE、INSERT或者DELETE。当你创建或者销毁表和索引时,SQLite 系统将自动更新它。

注意,所有的临时表都不会出现在 SQLITE_MASTER 中,临时表及其索引的 schema 将被存储在另一个被称为 SQLITE_TEMP_MASTER 的表中。SQLITE_TEMP_MASTER 只对创建它的程序可见,除此之外它用起来跟 SQLITE_MASTER 没有任何区别。

可以使用以下语句,来查看当前数据库中所有永久的和临时的表:

SELECT name FROM 

   (SELECT * FROM sqlite_master UNION ALL

    SELECT * FROM sqlite_temp_master)

WHERE type='table'

ORDER BY name;

3. 问:怎么在一个表中添加和删除一个域(列)?

3. 答:抱歉,作为一个正常的数据库,SQLite 不能删除表中已存在的域。

换言之,SQLite 的 ALTER TABLE 指令只能用来①在表的末尾添加一个新的域和②修改表的名称。如果你想要对表做出更加出格的行为,对不起你只能另建一张表。

例如,你有个表 t1 拥有三个域:"a"、"b" 和 "c",此时你想删除域 c ,你可以这么做:

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;

哇哇?!搞什么鬼为什么这么麻烦? 就不能提供一个 DELETE COLUMN 来一键删除么?

不能!因为像 删除 这样的面目狰狞的可怕命令,对于视安全比生命更为重要的数据库而言是不能原生支持的,记录在数据库的东西,就像胎记一般,不会因为你洗个澡就洗没了,实在不想要不嫌麻烦不怕痛可以动刀子切掉,那大家都没话说。

4. 问:我在数据库中删除了很多数据,但数据库却一点儿没变小,谁出来说句公道话?

4. 答:别急听我说,当你从 SQLite 数据库中删除信息时,SQLite 内部会记录这个空出来的区域,以便于下次你插入新数据时可以使用。但在你没有断开数据库链接(close)之前,这片存储区域暂时不还给操作系统。

这好像是很多收押金的APP的套路。。。

对于强迫症患者来说,这不是一件好事,他们的理想情况是,我一旦删除数据,必须要看到实实在在的数据库变小!并且一定要删多少小多少,因为这样才能感觉整个世界尽在掌握之中,怎么才能做到呢?也好办,只要一个 SQL 命令就可以了:

VACUUM;

如果你有更高的要求,你要求每次删除数据时必须强迫 SQLite 自动释放相应的存储空间,那可以使用 auto_vacuum 来达到地。

PRAGMA auto_vacuum = FULL;

但是凡事都是要付出代价的,每次严格缩减存储空间带来的后果除了使得 SQLite 系统变慢之外,在缩减空间时实际上还会产生最多两倍于已用空间大小的临时存储空间需求。

5. 问:SQLite那么棒,我能不能偷偷把它用到我的商业项目中,额。。。我指的是不掏任何费用的情况下?

5. 答:虽然问得略显猥琐,但答案是肯定的。

SQLite是彻底的开源,你不需要为他付出任何费用,它的作者在源码的开头处仅仅写下对使用它的人的三个“祝福”:

?愿你用来行善除恶

?愿你原谅自己并宽恕他人

?愿你宽心与人分享,所取不多于所施。

可能你会觉得作者矫情,但请注意,SQLite 不是普通的软件,世界上所有的安卓手机和苹果手机全部都使用 SQLite,这还仅仅是手机而已,还有海量电子设备都用到了这款快准狠的数据库!想想吧!作者为了开源事业,放弃了多么大的现实利益!敬佩!

6. 问:怎么在字符串中包含一个单引号?

6. 答:SQL 标准使用单引号来引用字符串,因此在字符串中包含单引号是需要特殊的写法:写两遍。请看:

INSERT INTO t values('苹果''香蕉');

注意到插入的字符串中红色的一堆单引号,它表示一个单引号,因此他相当于插入了这样的字符串:

苹果'香蕉

今天先聊到这儿,后续关于SQLite的常见问题会陆续更新。欢迎小伙伴关注、转发、点赞、收藏、吐槽、扔鸡蛋……

嘘!听说识别下面二维码进入 微店秘籍酷 能上天遁地,不信你试试!

微信原文: https://mp.weixin.qq.com/s?__biz=MzAxNzYzMTU0Ng==&mid=2651289233&idx=1&sn=3994dc7fd73c6db5755e6e1496cbe67d&chksm=801146c4b766cfd25445ddf4981fc6e36662e5ee82d11049780722d8f1f7c9e0d9941b2c2b39#rd

原文地址:http://blog.51cto.com/vincent040/2055891

时间: 2024-08-30 12:46:02

关于女神SQLite的疑惑(2)的相关文章

VS15 preview 5打开文件夹自动生成slnx.VC.db SQLite库疑惑?求解答

用VS15 preview 5打开文件夹(详情查看博客http://www.cnblogs.com/zsy/p/5962242.html中配置),文件夹下多一个slnx.VC.db文件,如下图: 本文件是SQLite文件,通过Navicat Premium打开,配置如下: 打开如下: 一共有14张数据表.其中以下3张表有数据: 各个表与字段含义,从官网也没有找到相关解释,还有待考证:其中个别表可以从命名来理解,例如properties,表示属性.有知情者请告诉一二,如向本人获取Navicat P

Python解析excel文件并存入sqlite数据库

功能:1.数据库设计 建立数据库2.Python解析excel文件3.Python读取文件名并解析4.将解析的数据存储入库 一 建立数据库 根据需求建立数据库,建立了两个表,并保证了可以将数据存储到已有的数据库中,代码如下: import sqlite3 def createDataBase(): cn = sqlite3.connect('check.db') cn.execute('''CREATE TABLE IF NOT EXISTS TB_CHECK (ID integer PRIMA

SQLite 疑惑

1 Rtree运行于SQLite的哪一层? 在这个框架中我们尝试去了解Rtree作为一个单独的模块是如何 融入到整个框架中的,到底是在core层,还是在Backend层,

(转)SQLite数据库增删改查操作

原文:http://www.cnblogs.com/linjiqin/archive/2011/05/26/2059182.html SQLite数据库增删改查操作 一.使用嵌入式关系型SQLite数据库存储数据 在Android平台上,集成了一个嵌入式关系型数据库--SQLite,SQLite3支持NULL.INTEGER.REAL(浮点数字).TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n).char(n).d

Sqlite学习笔记(二)&&性能测试

测试目标 获取SQlite的常规性能指标 测试环境 CPU:8核,Intel(R) Xeon(R) CPU E5-2430 0 @ 2.20GHz 内存:16G 磁盘:SSD Linux 2.6.32 SQlite最新版本3.8.11 测试场景 1)  主键查询测试 2)  主键更新测试 3)  批量导入测试 初始化 1)  测试表结构 CREATE TABLE user( id integer primary key autoincrement, c1 int, c2 varchar(1000

SQLite数据库增删改查操作

一.使用嵌入式关系型SQLite数据库存储数据 在Android平台上,集成了一个嵌入式关系型数据库--SQLite,SQLite3支持NULL.INTEGER.REAL(浮点数字). TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n). char(n).decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型. SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段

[转]android sqlite db-journal文件产生原因及说明

今天在android中将sqlite的数据库文件生成在SD卡上的过程中,发现生成的.db文件的旁边生成了一个大小为0的与数据库文件同名的.db-journal文件,不明白此文件的用途,于是google了sqlite的官方文档. 发现该文件的用途如下: 该文件是sqlite的一个临时的日志文件,主要用于sqlite事务回滚机制,在事务开始时产生,在事务结束时删除:当程序发生崩溃或者系统断电时该文件将留在磁盘上,以便下次程序运行时进行事务回滚. 但是我创建数据库时将事务结束了,同时程序也没有崩溃,为

android之SQLite

android之存储篇_SQLite数据库_让你彻底学会SQLite的使用 Android之SQLite数据库的使用 SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么. 例如:可以在Integer类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值. 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数, 当向这种字段保存除整数以外的数据时,将会产生错误. 另外, SQLite 在

关于.NET C#调用Sqlite的总结二

关于.NET C#调用Sqlite的总结一 在上一篇中我一直疑惑为什么我在使用多层架构进行开发时总是会报些莫名的错误,难道要使用Sqlite就不能分层吗?只能将UI.业务逻辑.数据访问统统都要写在一层里吗?当真不能分层开发吗? 抱着不信邢的心念,下了班回到家又继续研究起来.经过一翻折腾又有些小收获,在此继续分享下! 我的测试代码结构如下: 1.经过测试不管你的机器是x86还是x64的,只要到Sqlite官网下载对应.NET Framework版本的Win32版的就可以了.我自己尝试引用跟自己机器