SQLite 学习笔记.
一.SQLite 安装
访问http://www.sqlite.org/download.html下载对应的文件.
1.在 Windows 上安装 SQLite.需要下载 sqlite-shell-win32-*.zip 和 sqlite-dll-win32-*.zip 压缩文件.
创建文件夹 C:\sqlite,并在此文件夹下解压上面两个压缩文件,将得到 sqlite3.def、sqlite3.dll 和 sqlite3.exe 文件.
添加 C:\sqlite 到 PATH 环境变量,最后在命令提示符下,使用 sqlite3 命令,将显示如下结果.
C:\>sqlite3
SQLite version 3.7.15.2 2013-01-09 11:53:05
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
2.在 Linux 上安装 SQLite
几乎所有版本的 Linux 操作系统都附带 SQLite.所以,只要使用下面的命令来检查您的机器上是否已经安装了 SQLite.
如果没有安装,则需要从源代码区下载 sqlite-autoconf-*.tar.gz.
$tar xvfz sqlite-autoconf-3071502.tar.gz
$cd sqlite-autoconf-3071502
$./configure --prefix=/usr/local
$make
$make install
二.SQLite 命令
在命令行下输入sqlite3进入sqlite shell模式.后面可接一个文件名,用于创建本地文件(在当前目录中,如命令提示符启动时的目录),否则只在内存中处理.
.help 或 .h : 查询帮助信息,返回可用的命令. 也可以在命令行中输入sqlite3 -help,在命令行中输出sqlite的相关信息.
.exit 或 .e 或 .quit 或 .q : 退出sqlite模式
.backup ?DB? FILE 备份 DB 数据库(默认是 "main")到 FILE 文件。
.bail ON|OFF 发生错误后停止。默认为 OFF。
.databases 列出附加数据库的名称和文件。
.dump ?TABLE? 以 SQL 文本格式转储数据库。如果指定了 TABLE 表,则只转储匹配 LIKE 模式的 TABLE 表。
.echo ON|OFF 开启或关闭 echo 命令。
.exit 退出 SQLite 提示符。
.explain ON|OFF 开启或关闭适合于 EXPLAIN 的输出模式。如果没有带参数,则为 EXPLAIN on,及开启 EXPLAIN。
.header(s) ON|OFF 开启或关闭头部显示。
.import FILE TABLE 导入来自 FILE 文件的数据到 TABLE 表中。
.indices ?TABLE? 显示所有索引的名称。如果指定了 TABLE 表,则只显示匹配 LIKE 模式的 TABLE 表的索引。
.load FILE ?ENTRY? 加载一个扩展库。
.log FILE|off 开启或关闭日志。FILE 文件可以是 stderr(标准错误)/stdout(标准输出)。
.mode MODE 设置输出模式,MODE 可以是下列之一:
csv 逗号分隔的值
column 左对齐的列
html HTML 的 <table> 代码
insert TABLE 表的 SQL 插入(insert)语句
line 每行一个值
list 由 .separator 字符串分隔的值
tabs 由 Tab 分隔的值
tcl TCL 列表元素
.nullvalue STRING 在 NULL 值的地方输出 STRING 字符串。
.output FILENAME 发送输出到 FILENAME 文件。
.output stdout 发送输出到屏幕。
.print STRING... 逐字地输出 STRING 字符串。
.prompt MAIN CONTINUE 替换标准提示符。
.read FILENAME 执行 FILENAME 文件中的 SQL。
.schema ?TABLE? 显示 CREATE 语句。如果指定了 TABLE 表,则只显示匹配 LIKE 模式的 TABLE 表。
.separator STRING 改变输出模式和 .import 所使用的分隔符。
.show 显示各种设置的当前值。
.stats ON|OFF 开启或关闭统计。
.tables ?PATTERN? 列出匹配 LIKE 模式的表的名称。
.timeout MS 尝试打开锁定的表 MS 微秒。
.width NUM NUM 为 "column" 模式设置列宽度。
.timer ON|OFF 开启或关闭 CPU 定时器测量。
创建数据库 命令行输入"sqlite3 文件名",即创建了一个数据库.但是这个文件不会立即创建,需等到添加数据,或退出sqlite时才保存.
三.SQLite 语法
1.命令: 每条命令由一系列的记号组成,以";"结束.记号可以是常量,关键字,标识符,表达式或特殊符号.
2.常量: 字符串常量,数字常量,二进制常量.
字符串常量以单引号引起来.也可以是双引号,但SQL标准是单引号,所以建议都使用单引号.
数字常量可以是整数,如1,-1,2.3等.
二进制常量使用x‘0000‘的表示方法.其中每位是一个16进制数.二进制值必须是16进制数的整数倍(8bits),如x‘1f‘,x‘2312‘,x‘ffeedd‘
3.关键字和标识符: 不区分大小写.关键字不能作为标识符使用.如select,update,insert,into,create,drop,begin等等.
4.注释: 以--开头,或/* */形式包含
四.SQL命令
1.创建表.create table
create [temp|temporary] table table_name (column_definitios [,constaraints]);
temp或temporary声明的是临时表,只存活于当前会话,连接断开时自动销毁.
方括号内是可选项.
管道符|表示2选1;
必须包含至少一个表和一个字段.table_name为表名,小括号内是字段名列表,字段之间以","分隔.每个字段由"名称 类型 约束条件(可选)"组成.
例如,如下创建了contacts表,其中_id是自增主键,name声明为text,约束不能为null,且排序不区分大小写.phone默认为UNKNOWN.表一级约束是unique,定义在name和phone上.
CREATE TABLE contacts( _id integer primary key autoincrement,
name text not null collate nocase,
phone text not null default ‘UNKNOWN‘,
unique(name,phone) );
2.修改表.alter table可以修改表名或增加字段
alter table table_name {rename to new_table_name | add column colunm_def};
大括号内表示可选项,只能2选1.语句中并不需要包含大括号.
colunm_def为新增的列定义,与create table要求一致.
例如,如下新增一个列email.
alter table contacts add column email text not null default ‘ ‘;
表还可以由select语句创建,这样在创建表结构的同时创建数据.
3.插入数据. insert into
(1)插入单行
insert into table_name(column_list) values (value_list);
insert into table_name values(value_list); 此形式中value_list中的值需要与创建表的字段一一对应.
table_name为插入的表名. column_list表示需要插入的列列表,value_list是对应的值列表,它们都用","分隔.字段必须存在于表中.如
sqlite> insert into phone(contacts_id, data) values(2, 223);
在column_list不指定自增长的字段(primary key autoincrement),或指定了但value_list对应的值为null,则该字段会自动增长.
(2)插入一组行
使用子查询添加: 在value_list中对某一个数据采用子查询的方式,得到一组值.如
insert into phone values(null, (select _id from contacts), null);
使用select形式的insert语句可以一次插入多行,只要数据字段匹配.
sqlite> CREATE TABLE phone2 (_id integer primary key autoincrement, contacts_id integer);
sqlite> insert into phone2 select phone._id,phone.contacts_id from phone;
(3)插入多行数据
创建时插入数据.create table new_table_name as select * from table_name.这样将复制table_name一份数据到新到表new_table_name中.
如 sqlite> create table phone3 as select * from phone2;
但是,这种形式创建的新表,原约束及类型都不是旧表的类型.自增字段不会创建,索引也不会创建,unique也不会有.
4.更新数据. update
update table_name set update_list where predicate;
update_list是一个或多个赋值字段的列表,形式为:column1=value1,column2=value2,...
where子句和select命令相同.
如: sqlite> update phone set data = 10087, contacts_id = 4 where _id == 3;
update命令必须注意unique约束,如不能修改primary key的值为重复项,否则会报错.
5.删除记录 delete
delete from table_name where predicate;
where子句和select命令相同.不带where子句的语句将删除整个表.
注意:
(1)delete语句删除后并不释放空间.
(2)primary key autoincrement字段的最大值也不会恢复为0,会保留旧值,如需恢复,需要删除或更新sqlite_sequence下的值.
sqlite> delete from phone where _id = 14;
5.查询数据库.select命令.select命令输出可作为另一个select的输入,如select name from (select * from contacts).
select [distinct] heading from tables where predicate group by columns having predicate order by columns limit count offset count;
每个关键字如from,where,having,group by,order by,limit等都是一个单独的子句,每个子句由关键字和跟随的参数构成.后面的子句以前面子句产生的结果进行输入处理.
distinct去掉重复.
select distinct name from contacts;语句将列出name,所有行的name值都不一样.
from子句是由逗号分隔的一个或多个表,视图.如果指定多个表,它们会组合形成单一的关系.
where子句参数predicate由逻辑表达式组成,它们定义了行的选择标准.
如select * from contacts where _id < 3 and email != ‘ ‘;
逻辑表达式中,可以包由以下几种组成
(1)比较指定条件,如==(或=),!=(或<>),>,<,>=,<=,!<(不小于),!>(不大于).
(2)逻辑运算符
AND 运算符允许在一个 SQL 语句的 WHERE 子句中的多个条件的存在.
BETWEEN 运算符用于在给定最小值和最大值范围内的一系列值中搜索值.
EXISTS 运算符用于在满足一定条件的指定表中搜索行的存在.
IN 运算符用于把某个值与一系列指定列表的值进行比较.
NOT IN 运算符的对立面,用于把某个值与不在一系列指定列表的值进行比较.
LIKE 运算符用于把某个值与使用通配符运算符的相似值进行比较,不区分大小写.如 like ‘%h%‘ 将选出该值中包含h的.
GLOB 运算符用于把某个值与使用通配符运算符的相似值进行比较,大小写敏感的即区分大小写。
NOT 运算符是所用的逻辑运算符的对立面。比如 NOT EXISTS、NOT BETWEEN、NOT IN,NOT LIKE等等。它是否定运算符。
OR 运算符用于结合一个 SQL 语句的 WHERE 子句中的多个条件。
IS NULL 运算符用于把某个值与 NULL 值进行比较。
IS 运算符与 = 相似。
IS NOT 运算符与 != 相似。
|| 连接两个不同的字符串,得到一个新的字符串。
UNIQUE UNIQUE 运算符搜索指定表中的每一行,确保唯一性(无重复).
在LIKE和GLOB中,%可匹配0个或多个任意字符,_可匹配一个任意字符.
(3)位运算符
& 如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中.
| 如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中.
~ 二进制补码运算符是一元运算符,具有"翻转"位效应.
<< 二进制左移运算符。左操作数的值向左移动右操作数指定的位数.
>> 二进制右移运算符。左操作数的值向右移动右操作数指定的位数.
GROUP BY子句用于与 SELECT 语句一起使用,来对相同的数据进行分组.
产生的效果是,指定列不会出现两个重复的值.如name字段都含有"中国移动",则只会出现一个.
利用聚合函数,还可以对每个组的数据计算聚合值.如
select name,count(*) from contacts group by name;语句将显示不同的name出现的次数
HAVING 子句允许指定条件来过滤将出现在最终结果中的分组结果.例如,以下语句将选出字段name相同且个数大于2的数据.
select * from contacts group by name having count(2) > 2;
order by子名指定以某些列进行排序.asc升序(默认),desc降序.当第一个出现重复时,以后面第二,第三,...去排序.
limit和offset限定大小和范围.limit指定返回的最大记录数量.offset指定偏移的记录数.
limit和offset一起使用时,可以使用","代替offset.注意:limit 2,1表示的是limit 1 offset 2.
多级选择
语法:select ... from left_table_name join_type right_table_name on join_condition;
实例:
sqlite> create table phone (_id integer primary key autoincrement, contacts_id integer, data text);
sqlite> select contacts.name, phone.data from contacts,phone where contacts._id = phone.contacts_id;
(1)内连接,找出同时存在于两个表中的元素.
select ... from table_1 inner join table_2 on conditional_expression ...;
sqlite> select * from contacts inner join phone on contacts._id = phone.contacts_id;
(2)交叉连接,不需要连接条件,只是简单的组合在一起.
SELECT ... FROM table_1 CROSS JOIN table2 ...
sqlite> select * from contacts cross join phone;
(3)外连接(OUTER JOIN)是内连接(INNER JOIN)的扩展.SQL标准定义了三种类型的外连接:LEFT\RIGHT\FULL,但SQLite只支持左外连接(LEFT OUTER JOIN).
左外连接 SELECT ... FROM table1 LEFT OUTER JOIN table2 ON conditional_expression ...;
sqlite> select * from contacts left outer join phone on contacts._id = phone.contacts_id;
左外连接试图把所有contacts中_id与phone中contacts_id相同的所有行进行连接关系的匹配,找出所有匹配的行.但是contacts中没有匹配phone的行仍会出现在结果中,phone中没有提供相应的行,以null补充.
(4)自然连接,通过表中共有的字段名将两个表连接起来.因此使用自然连接时,不用添加连接条件就能取得内连接的结果.
自然连接由于两个表的列改动而出现结果的不确定性,因此尽量不使用.
名称和别名.
连接表时,如果两个表中存有同样名称的字段时,如使用select _id就会产生歧义.因此可用 table_name.field 的方法避免.
另一种方式是使用别名.如select f._id, t._id from contacts f, phone t where f._id == t.contacts_id;
其中contacts 的别名是f,phone的别名是t.
条件结果.
第一种,接收静态值并列出各种情况下的case返回值.
case value
when x then value_x
when y then value_y
else default_value
end
sqlite> select name || ‘_‘ || case _id when 1 then ‘a‘ else ‘b‘ end description from contacts where length(description) > 6 order by _id;
其中||用于连接两个字符串,返回的值为description,where对description进行过滤.
第二种,允许when条件中有表达式.
case
when condition_1 then value_x
when condition_2 then value_y
else default_value
end
sqlite> select name || ‘_‘ || case when _id < 3 then ‘a‘ else ‘b‘ end description from contacts where length(description) > 6 order by _id;
函数.
SQLite提供了多种内置函数和聚合,可以用在不同的子句中.函数包括:数学函数如abs,字符串格式函数,和大小写转换函数upper及lower.
聚合是一类特殊的函数,它从一组记录中计算聚合值.如sum,avg,count,min,max等
select _id,upper(name),length(name) from contacts; 以_id,upper(name),length(name)分别显示每行数据.
select * from contacts where length(name) > 4; 选出name长度大小4的行
select count(*) from contacts; 计算所有行的数量.
聚合还可以把结果集分成多个组,然后计算每个组的聚合值.
处理 null值.
null是缺失信息的占位符,本身不是值,也不是空字符串.简单的说,null就是null.NOT NULL 表示列总是接受给定数据类型的显式值,这意味着不能为null.
(1)逻辑运算中的null.
AND: true AND null = null. false AND null = false. null AND null = null.
OR: true OR null = true. false OR null = null. null OR null = null.
其中true可用值为非0或非0的逻辑表达式代替,false用0或值为0的逻辑表达式代替.
可以使用select语句测试,如select null and 1;
(2)可以通过 is null 或 is not null 检测null是否存在.
(3)null不等于其它值,包括null.因此不能使用equal,greater than等函数进行比较.
(4)coalesce函数: 返回非null的第一个值.如sqlite> select coalesce (null, 1, null, 8); 将返回1
(5)nullif函数: 如果两个数相等则返回null,否则返回1.如
sqlite> select nullif(1, 1);
null
sqlite> select nullif(1, 3);
1
(6)使用null,需要注意断言和聚合中引用可能存在null值字段的查询.否则可能报错.
五.约束
1.unique唯一性约束.要求一个或一组字段所有值互不相同.
如下表中,id在每行中都不能相同.name和phone不能同时相同.
sqlite> create table phone5(id integer unique, name text not null default ‘‘, phone text not null default ‘UNKNOWN‘, unique(name, phone));
在sqlite中,null与null都不相同,因此可以同时放入两个null.
2.primary key主键约束.每个表只有一个主键,称为rowid(别名_rowid,oid),如果在创建表时指定了primary key约束,那么它就是rowid的另一个别名.
主键具有自动增长的功能.SQLite使用64位单符号整数主键,因此,最大值为0x7fffffffffffffff.达到最大值时rowid会回收已删除的值.
但指定了autoincrement的主键则不会,SQLite也会在一个名为sqlite_sequence的系统表中记录该字段当前的最大值.达到最大值时,后面的insert语句中返回SQLITE_FULL错误.
sqlite_sequence中保存两个字段,name为表名,seq为自动主键的最大值.
主键约束也可以定义在多个字段中,此时同唯一性约束.如
create table pkey(x text, y text, primary key(x, y));
SQLite总是在内部维护rowid,因此建议使用实际字段作为主键字段,即创建表时定义主键字段.
3.default 默认值.保证该字段有值,并在需要时出现.如果没有默认值,insert语句中没有指定值,则为null.default还可以指定三种默认的格式:
default current_time 生成当前时间 (HH:MM:SS)
default current_data 生成当前日期 (YYYY-MM-DD)
default current_timestamp 生成一个日期时间的组合 (YYYY-MM-DD HH:MM:SS)
如下面的语句:
sqlite> create table phone7(name text, time1 text not null default current_time, time2 text not null default current_date, time3 text not null default current_timestamp);
sqlite> insert into phone7(name) values(‘haha‘);
sqlite> .headers on
sqlite> .mode column
sqlite> select * from phone7;
name time1 time2 time3
---------- ---------- ---------- -------------------
haha 14:15:12 2016-01-20 2016-01-20 14:15:12
4.not null 约束.确保该字段不为null.insert语句中不能向该字段插入null,update语句也不能修改为null.
使用not null约束的字段,如果没有指定default,则在insert时必须向该字段赋值,因为系统提供的默认值是null.
处理未知数据和not null约束的实用方法是给字段设定默认值.这样就insert语句就可以安全的使用默认值,也可以将null排除在外.
5.check 约束.允许定义表达式来测试要插入或者更新的字段值.如果该值不满足表达式的标准,则会报约束违反错误.可直接在字段后面写约束条件,或者作为表定义中的一条单独约束.
sqlite> create table phone9(_id integer primary key autoincrement, phone text check( length( phone ) > 7) );
或 sqlite> create table phone9(_id integer primary key autoincrement, phone text, check( length(phone) > 7 ));
sqlite> insert into phone9(phone) values(‘123‘);
Error: CHECK constraint failed: phone9
check 表达式可以根据字段的值进行评估.如:
sqlite> create table foo(x integer, y integer check(y>x), z integer check (z>abs(y)));
6.外键约束.确保一个表中的关键值必须从另一个表中引用,且该数据必须在另一个表中实际存在.如父子关系,主从关系,以及订单和商品关系等.
语法: create table table_name(column_definition references foreign_table_name(column_name) on {delete|update} integrity_action [not] deferrable [initially{deferred|immediate},] ... );
如:
sqlite> CREATE TABLE food_types(id integer primary key, name text);
sqlite> CREATE TABLE foods(id integer primary key, type_id integer references food_types(id) on delete restrict deferrable initially deferred, name text);
references foreign_table_name(column_name): 表示关联的表中的字段.
on delete 或 on update: 删除或添加时的行为.
integrity_action: 行为规则.如下
set null: 如果父值被删除了或者不存在,剩余的子值将改为null.
set default: 如果父值被删除了或者不存在,子值修改为默认值.
cascade: 更新父值时,更新力有预知匹配的子值.删除父值时,删除所有子值.注意:删除功能可能会出现意想不到的效果.
restrict: 更新或删除父值时,阻止或终止事务.
no action: 只观察变化,不做任何变化.
deferrable initially deferred或immediate: deferred延迟到事务结束执行,immediate立即执行.
在windows平台下,测试外键约束,没有起作用.
7.排序规则.collate关键字定义排序的规则.
(1)binary(默认),使用c函数memcmp逐字节进行比较,因此是大小写敏感的.
(2)nocase,大小写不敏感的的排序.
(3)reverse,与默认规则相反,用来测试.
CREATE TABLE seq(_id integer primary key autoincrement, data1 text, data2 text collate nocase, data3 text collate reverse);
8.存储类,即原始的5个基本类型integer,real,text,blob,null
NULL NULL值.
INTEGER 整数,根据值的大小存储在 1、2、3、4、6 或 8 字节中.
REAL 实数,存储为8字节的IEEE浮点数字.
TEXT 文本字符串,使用数据库编码(UTF-8、UTF-16BE 或 UTF-16LE)存储.默认最大值为 1000,000,000 字节.
BLOB blob数据,完全根据它的输入存储.默认最大值为 1000,000,000 字节.
SQLite判断类型的方法和顺序:
语句中用""或‘‘包含的文字为text.
只有数字,没有小数点或浮点数符号,为integer,否则为real.
null或NULL表示null值.
格式为x‘ABCD‘或X‘ABCD‘,其中ABCD为16进制数,则为blob.
函数typeof方法可返回值的类型.
sqlite> select typeof(‘sss‘);
typeof(‘sss‘)
一个字段定义为了某个存储类,但仍可能存储其它存储类的值.排序时采用以下规则:
(1)null为最小值.任何非null值都null值大.null值之间没有具体的排序顺序.
(2)integer和real通过数值大小进行比较排序.
(3)text比integer或real值大,text之间由字段定义的排序规则进行比较.
(4)blob比text值大,blob之间采用c memcmp()函数比较.
9.索引.索引是用来在某种条件下加速查询的结构.索引会增加数据库的大小;对表insert,update,delete修改时,也需要对相应的索引进行修改.
语法: create [unique] index index_name on table_name (columns);
index_name是索引名称,columns是table_name中的字段,以","分隔.
columns中也可以指定对列排序.
unique要求索引中的所有值必须是唯一的.这会在insert或update时,要求相应的字段不能同时相同.
删除索引: drop index index_name;
查询表的索引: .schema table_name 或 .indices table_name
注意: 一定要在理由能确保索引可提高性能时才使用索引,以下几个情况都应该避免使用索引:
在较小的表上; 在有频繁的大批量的更新或插入操作的表上; 在含有大量的 NULL 值的列上; 在频繁操作的列上。
六.触发器.事件发生时,触发器负责启动SQL命令.当触发器相关联的表删除时,自动删除触发器
语法:
create [temp|temporary] trigger trigger_name [before|after] [insert|update|update of columns] on table_name
begin
action
end;
before|after: 指定是在事件发生前还是发生后执行.
insert|update|update of columns: 事件在表table_name中执行的命令.
action:具体要回调执行的行为,由一系列的SQL命令组成.
如下例:
CREATE TABLE foo(a integer primary key autoincrement, b text, c text, d text collate nocase);
CREATE TRIGGER foo_insert after insert on foo
begin
update foo set c=b, d=b;
end;
更新触发器,可以在表的某个字段上定义,这样在该字段有修改行为时,会自动触发相应的trigger.
create trigger trigger_name [before|after] update of column on table begin action end;
CREATE TRIGGER foo_update after update of b on foo
begin
update foo set c=b, d=b;
end;
七.事务
事务由3个命令控制:begin,commit,rollback.
begin: 开始一个事务,begin之后的所有操作都可以取消.如果连接终止前没有发出commit,也会被取消.
语法: begin [deferred | immediate | exclusive] transaction; 或 begin; 相当于deferred
commit: 提交事务,执行所有begin到commit之间的所有操作.
rollback: 取消所有操作.
如果不显示的使用这3个命令,SQLite中每条命令都会自动使用begin...commit/rollback,如果执行成功则执行ommit自动提交,出错则rollback回滚.
savepoint pos ,保存执行的点.使用 rollback to pos ,可恢复到 pos以前的状态.
1.冲突解决.SQLite提供了5种可能的冲突解决策略.默认策略为abort.
replace: 违反唯一性约束时,将记录删除,以插入或修改的新记录代替,SQL继续执行,不报错.但删除触发器不会触发.
违反 not null 约束时, 使用该字段的默认值代替null.如果没有默认值,则使用abort策略.
ignor: 约束违反时,命令继续执行,违反约束的行不变.不报错.
fail: 约束违反时,终止命令,但不恢复违反之前已修改的记录.
abort: 约束违反时,恢复到命令所做的所有改变,并终止.
rollback:约束违反时,执行回滚,终止当前命令和整个事务.这将导致单个约束违反引起整个事务中执行的所有操作都回滚.
2.冲突使用.冲突可以在insert, update, create table, create index中指定.如
insert or resolution into table_name ....
update or resolution table_name ....
在表定义时也可为某个字段指定冲突,在约束中增加 on conflict resolution, 如
sqlite> create temp table cast(id integer unique on conflict rollback);
3.数据库锁
数据库锁有5种状态,每个连接在同一时刻只能有一种状态,除了未加锁,都有一个锁与之对应.
未加锁(unlocked): 数据库初始状态,此时没有访问数据库,即使调用了begin开始事务也如此.
共享(shared): 一个连接想读数据,首先需要取得共享锁.多个读数据连接可以同时取得共享锁,即共享锁可以有多个.
预留(reserved): 一个连接想写数据,首先需要取得预留锁,同一时刻只能有一个预留锁.预留锁不会阻止其它连接取得共享锁.
取得预留锁之后可以写数据,此时数据保存在缓冲区,并不保存到数据库文件.
未决(pending): 写数据连接提交数据时会先取得未决锁,此时其它连接不能取得共享锁,
但拥有共享锁的连接还可继续读数据,写数据连接等到所有共享锁释放后提升为排它锁.
排它(exclusive): 写数据连接需要取得排它锁时,才能往数据库文件中保存数据.
4.事务的类型
deferred: 直到使用时才获取锁,多个连接可以在同一时刻未创建锁的情况下开始deferred事务.
这种方式下,第一个读数据连接取得共享锁,第一个写数据连接取得保留锁.
immediate: 采用这种方式,会在begin时试图取得预留锁.如果成功,其它连接不能写数据,也不阻止已取得共享锁的连接读数据,但会阻止新的连接读数据.
此时,其它任务执行事务begin [immediate | exclusive]将会返回SQLITE_BUSY错误.
同时,如果其它读事务没有退出时,也不能提交,否则也会返回SQLITE_BUSY错误.
exclusive: 采用这种方式,会试图取得排它锁.一旦成功,其它连接就不能读写,此时可进行任意的读写操作.
使用的准则是,如果数据库没有其它连接,使用begin就足够了,但是如果存在其它写数据连接,就得使用immediate或exclusive开始事务.
八.其它常见问题
1.自动主键增加到Long最大值时再添加数据会报错Error: database or disk is full.
在Android中会报异常,android.database.sqlite.SQLiteFullException: database or disk is full (code 13).
遇到这种情况下,需要在删除表的同时将自动主键的值进行重新设置.
如何将自增字段的值重新设置为1.字段带有primary key autoincrement约束的表,sqlite将为其创建一个隐藏的表sqlite_sequence.
sqlite_sequence记录了当前数据库文件中所有表的自动主键的最大值.删除表后删掉该值或设置为0即可重置表的自动主键值.
如contacts2.db的信息如下表.
sqlite> select * from sqlite_sequence;
name seq
---------- ----------
mimetypes 20
directorie 1
accounts 8
raw_contac 1799
data 6425
contacts 2639
groups 12
agg_except 1122
data_usage 90
calls 620
photo_file 3
执行语句:
sqlite> delete from calls;
sqlite> update sqlite_sequence set seq = 0 where name == ‘calls‘; 或 delete from sqlite_sequence where name == ‘calls‘;
2.Android中如何取得自增字段的最大值?
select last_insert_rowid();语句在android中将返回0.
可用以下语句代替: select max(primary_key_column) from table_name;或 查询sqlite_sequence表.如
sqlite> select max(_id) from contacts;
max(_id)
4
在Android中示例代码如下:
public long getMaxId() {
long id = 0;
SQLiteDatabase db = null;
try {
db = mSqliteHelper.getWritableDatabase();
String sql;
// sql = "select * from sqlite_sequence";
sql = "SELECT max(_id) as max_id FROM " + PersonSQLiteHelper.TABLE_NAME;
Cursor cursor = db.rawQuery(sql, null);
if (cursor != null) {
if (cursor.moveToNext())
id = cursor.getLong(0);
cursor.close();
}
} finally {
if (db != null)
db.close();
}
return id;
}
SELECT max(_id) FROM table_name;
参考资料:http://www.runoob.com/sqlite/sqlite-null-values.html
《SQLite权威指南(第2版)》