php sqlite 问题,php SQLite学习笔记与常见问题分析

线程安全吗?线程是魔鬼(Threads are evil)。 避免使用它们。SQLite是线程安全的。由于很多用户会忽略我们在上一段中给出的建议, 我们做出了这种让步。但是,为了达到线程安全,SQLite在编译时必须将SQLITE_THREADSAFE预处理宏置为1。在Windows和Linux上,已编译的好的二进制发行版中都是这样设置的。如果不确定你所使用的库是否是线程安全的,可以调用sqlite3_threadsafe()接口找出。在3.3.1版本之前,一个 sqlite3结构只能被用于调用sqlite3_open创建的同一线程。你不能在一个线程中打开数据库,然后将数据库句柄传递给另外一个进程使用。这主要是由于在好多通用的线程实现(如RedHat9)中的限制引起的(是Bug吗?)。特别的,在有问题的系统上,一个进程创建的fcntl()锁无法被其它线程清除或修改。 所以,由于SQLite大量使用fcntl()锁做并发控制,如果你在不同的线程间移动数据库连接,就可能会出现严重的问题。在3.3.1版本上,关于在线程间移动数据库连接的限制变得宽松了。 在它及以后的版本中,只要连接没有持有fcntl()锁,在线程间移动句柄是安全的。 如果没有未决的事务,并且所有的语句都已执行完毕, 你就可以安全的假定不再持有任何锁。在UNIX中,在执行fork()系统调用时不应携带已打开的数据库进入子进程。那样做将会有问题。--------------------------------------------------------------------------------

(7)在SQLite数据库中如何列出所有的表和索引?如果你运行sqlite3命令行来访问你的数据库,可以键入“.tables”来获得所有表的列表。或者,你可以输入“.schema”来看整个数据库模式,包括所有的表的索引。输入这些命令,后面跟一个LIKE模式匹配可以限制显示的表。在一个C/C++程序中(或者脚本语言使用Tcl/Ruby/Perl/Python等) 你可以在一个特殊的名叫SQLITE_MASTER上执行一个SELECT查询以获得所有 表的索引。每一个SQLite数据库都有一个叫SQLITE_MASTER的表,它定义数据库的模式。SQLITE_MASTER表看起来如下:CREATE TABLE sqlite_master (

type TEXT,

name TEXT,

tbl_name TEXT,

rootpage INTEGER,

sql TEXT

);对于表来说,type字段永远是'table',name字段永远是表的名字。所以,要获得数据库中所有表的列表, 使用下列SELECT语句:SELECT name FROM sqlite_master

WHERE type='table'

ORDER BY name;对于索引,type等于'index', name则是索引的名字,tbl_name是该索引所属的表的名字。 不管是表还是索引,sql字段是原先用CREATE TABLE或CREATE INDEX语句创建它们时的命令文本。对于自动创建的索引(用来实现PRIMARY KEY或UNIQUE约束),sql字段为NULL。SQLITE_MASTER表是只读的。不能对它使用UPDATE、INSERT或DELETE。 它会被CREATE TABLE、CREATE INDEX、DROP TABLE和DROP INDEX命令自动更新。临时表不会出现在SQLITE_MASTER表中。临时表及其索引和触发器存放在另外一个叫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

--------------------------------------------------------------------------------

(8) SQLite数据库有已知的大小限制吗?在Windows和Unix下,版本2.7.4的SQLite可以达到2的41次方字节(2T字节)。老版本的为 2的31次方字节(2G字节)。SQLite版本2.8限制一个记录的容量为1M。SQLite版本3.0则对单个记录容量没有限制。表名、索引表名、视图名、触发器名和字段名没有长度限制。但SQL函数的名称(由sqlite3_create_function() API函数创建)不得超过255个字符。对有关SQLite限制的详细讨论,见limits.html。--------------------------------------------------------------------------------

(9)在SQLite中,VARCHAR字段最长是多少?SQLite不强制VARCHAR的长度。 你可以在SQLITE中声明一个VARCHAR(10),SQLite还是可以很高兴地允许你放入500个字符。 并且这500个字符是原封不动的,它永远不会被截断。--------------------------------------------------------------------------------

(10) SQLite支持二进制大对象吗?SQLite 3.0及以后版本允许你在任何列中存储BLOB数据。 即使该列被声明为其它类型也可以。--------------------------------------------------------------------------------

(11)在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;

--------------------------------------------------------------------------------

(12)我在数据库中删除了很多数据,但数据库文件没有变小,是Bug吗?不是。当你从SQLite数据库中删除数据时, 未用的磁盘空间将会加入一个内部的“自由列表”中。 当你下次插入数据时,这部分空间可以重用。磁盘空间不会丢失,但也不会返还给操作系统。如果删除了大量数据,而又想缩小数据库文件占用的空间,执行VACUUM命令。VACUUM将会从头重新组织数据库。这将会使用数据库有一个空的“自由链表”, 数据库文件也会最小。但要注意的是,VACUUM的执行会需要一些时间(在SQLite开发时,在Linux上,大约每M字节需要半秒种),并且,执行过程中需要原数据库文件至多两倍的临时磁盘空间。对于SQLite 3.1版本,一个auto-vacumm模式可以替代VACUUM命令。 可以使用auto_vacuum pragma打开。--------------------------------------------------------------------------------

(13)我可以在商业产品中使用SQLite而不需支付许可费用吗?是的。SQLite在public domain。对代码的任何部分没有任何所有权声明。你可以使用它做任何事。--------------------------------------------------------------------------------

(14)如何在字符串中使用单引号(')?SQL标准规定,在字符串中,单引号需要使用逃逸字符,即在一行中使用两个单引号。在这方面SQL用起来类似Pascal语言。SQLite尊循标准。如:INSERT INTO xyz VALUES('5 O''clock');

--------------------------------------------------------------------------------

(15) SQLITE_SCHEMA error是什么错误?为什么会出现该错误?当一个准备好的(prepared)SQL语句不再有效或者无法执行时,将返回一个SQLITE_SCHEMA错误。发生该错误时,SQL语句必须使用sqlite3_prepare() API来重新编译.在SQLite 3中,一个SQLITE_SCHEMA错误只会发生在用sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API执行SQL时。而不会发生在使用sqlite3_exec()时。 在版本2中不是这样。准备好的语句失效的最通常原因是:在语句准备好后, 数据库的模式又被修改了。另外的原因会发生在:数据库离线:DETACHed.数据库被VACUUMed一个用户存储过程定义被删除或改变。一个collation序列定义被删除或改变。认证函数被改变。在所有情况下,解决方法是重新编译并执行该SQL语句。 因为一个已准备好的语句可以由于其它进程改变数据库模式而失效,所有使用sqlite3_prepare()/sqlite3_step()/sqlite3_finalize() API的代码都应准备处理SQLITE_SCHEMA错误。下面给出一个例子:int rc;

sqlite3_stmt *pStmt;

char zSql[] = "SELECT .....";

do {

/* Compile the statement from SQL. Assume success. */

sqlite3_prepare(pDb, zSql, -1, &pStmt, 0);

while( SQLITE_ROW==sqlite3_step(pStmt) ){

/* Do something with the row of available data */

}

/* Finalize the statement. If an SQLITE_SCHEMA error has

** occured, then the above call to sqlite3_step() will have

** returned SQLITE_ERROR. sqlite3_finalize() will return

** SQLITE_SCHEMA. In this case the loop will execute again.

*/

rc = sqlite3_finalize(pStmt);

} while( rc==SQLITE_SCHEMA );

--------------------------------------------------------------------------------

(16)为什么ROUND(9.95,1)返回9.9而不是10.0?9.95不应该圆整(四舍五入)吗?SQLite使用二进制算术,在二进制中, 无法用有限的二进制位数表示9.95。使用64-bit IEEE浮点 (SQLite就是使用这个)最接近9.95的二进制表示是9.949999999999999289457264239899814128875732421875。所在,当你输入9.95时,SQLite实际上以为是上面的数字, 在四舍五入时会舍去。这种问题在使用二进制浮点数的任何时候都会出现。 通常的规则是记住很多有限的十进制小数都没有一个对应的二进制表示。 所以,它们只能使用最接近的二进制数。它们通常非常接近,但也会有些微小的不同,有些时候也会导致你所期望的不同的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值