InterBase7

Interbase7  

2010-09-29 00:11:13|  分类: 数据库|举报|字号 订阅


InterBase70还提供了新的API函数用来监测InterBase客户端版本,这些函数是:

isc_get_client_version()

isc_get_client_major_version()

isc_get_client_minor_version()

外部表的安全性进一步强化。在以前的版本中,外部表放置在何处并没有严格的要求,这就可能造成安全危险。InterBase70对此作了强化约
束,即外部表必须放置在规定的目录中,这个目录默认是InterBase安装目录下的ext子目录。如果你想放在其它目录,就必须在配置文件
ibconfig中通过EXTERNAL_FILE_DIRECTORY参数指定存放外部表的位置。

InterBase6.X是一个完全符合ANSI SQL92标准的数据库,但在此基础上又有些扩展,它引入了分隔标识符、大型精确数字类型、date类型、
time类型等一些新特性和新用法,它们与旧版本的InterBase不兼容,于是在InterBase6.X中引入了Dialects的概念帮助数据库端与客户端
解决如何对待这些新特性。
Dialect 1:按照InterBase5.X对待,确保对旧版本的数据库和客户端的兼容性。
Dialect 3:按照InterBase6.X对待,提供了对InterBase6.X新特性的完整支持。
Dialect 2:仅对客户端诊断用。
简言之,dialects是InterBase是否发挥其SQL新功能的标志。dialect 1不支持新功能,只有选择dialect 3,才能保证使用全部新功能。一定
要注意,数据库端和客户端两者的Dialect必须保持一致,如果不一致,数据库访问就会出现错误。

IBX是一组可以直接访问InterBase API函数的DELPHI、C++Builder组件,包括数据库访问操作和数据库管理两大类,可用于单层、两层、多层
结构程序中,为InterBase数据库应用开发提供了最快速和最灵活的控制。

InterBase6.X增添了如下的保留字:
COLUMN
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
DAY
EXTRACT
HOUR
MINUTE
MONTH
SECOND
SQL
TIME
TIMESTAMP
TYPE
WEEKDAY
YEAR
YEARDAY

Extract函数:
  可以使用Extract函数从数据库中抽取日期或时间。语法是:Extract(关键字 from 字段)。
其中:字段必须是日期或时间类型的,关键字可以是年、月、日、小时、分钟、秒等。但要注意关键字信息一定要被包含在字段中信息中。

InterBase6.X的gbak包含了版本5的gsplit的功能,并增添了多个选项,如允许数据库拥有者或者SYSDBA从多个文件中进行备份或恢复,允许
你设置数据库为只读模式,还可以执行数据库端的备份等等。
******************************************************************************************************************
InterBase7.0增加了新的ROWS子句以扩展Select,Delete,Update语句所能影响的记录的范围。其语法是:
ROWS <lower_val>[ TO <upper_val>][BY <step_val>][PERCENT][WITH TIES]。
一般情况下,ROWS和ORDER BY一起使用进一步将影响的数据行限制在lower_val和upper_val指定的范围内。ROWS子句的作用和
SQL SERVER2000中的TOP n差不多,但比TOP n更灵活、强大。
******************************************************************************************************************
IBX现在有一个新的类TIBOutputXML,允许你以XML的格式导出数据库中的数据。此外,两个API函数isc_dsql_xml_fetch()和
isc_dsql_xml_fetch_all(),也可以直接由客户端调用生成XML文档。这个功能将极大地方便WEB应用的开发。

InterBase安装完后自动生成一个超级用户SYSDBA,其密码是masterkey。这个超级用户拥有最高权限,而且你无法删除它。强烈建议你登录
后将其密码更改。

InterBase在其Bin目录中也提供了isql命令行交互工具,不要以为有了可视化的工具这个isql就一点用处没有了,有时候很多故障最终的确定
还要靠这个命令行工具。

InterBase有如下对象:
数据库(Database)、表(Table)、列(Column)、视图(View)、索引(Index)、域(Domain)、存储过程(Stored Procedure)、触发器(Trigger)、生成器(Generator)、缺省(Default)、规则(Rule)、约束(Constraints)、异常(Exception)、用户自定义函数(?)、BLOB过滤器(BLOB Filter)、角色(Role)。

InterBase支持如下的数据类型:
数字类型(整数:包括Integer,Smallint;浮点数:包括Float,Do le Precision;定点数:包括Numeric,Decimal)、日期时间类型(包括Date,Time,Timestamp)、字符类型(包括Char,Varchar)、布尔类型(BOOLEAN)、二进制类型(Blob)。

所谓业务规则是指为满足一定的业务运作而加在数据库上的某些约束、限制或者特定处理,其主要目的是确保数据符合企业业务管理的要求,
增强业务运行的效率,保证数据的完整性、安全性、一致性。业务规则一般包括:数据完整性、参照完整性以及确保业务运行的其它要求。
在InterBase中,有很多方法可以实现业务规则,如:规则、约束、缺省、触发器、存储过程等。

索引可以使基于关键条件的查询非常迅速,但也会使数据的更新和存储变慢。你需要根据实际情况合理地进行平衡。一种优化的观点是尽量不
要在同一个字段上创建多个索引,而是要在不同的字段上创建不同的索引。如果一个查询包含多个字段,InterBase会自动使用多个索引加快
查询速度。这要比在多个字段上创建一个联合索引性能好得多。影响索引及数据存取的因素是数据页的大小。增加数据页的大小,可以使每页
上存储更多的数据,从而减少索引使用的数据页的数目,即索引树变浅。如果你有一个索引其深度超过4层,你就应该考虑增大数据页的大小;
如果建立在变化频度较高的数据上的索引深度少于3层,你就应该减小数据页的大小。

当InterBase读取数据页时,它总是把数据页放到它的高速缓存里。通常,缺省的高速缓存大小是256个缓冲区大小,一般情况下是够用的。如
果一个查询包含超过5个表的联合,InterBase会自动增加高速缓存的大小。你可以增加高速缓存的默认大小,以便有更多的空间存放更多的数
据页而不必等待上一个数据页的释放。增加数据库缺省高速缓存大小的命令是:
gfix -b?rs n database_name
n是大小,database_name是数据库名称。

Create Database的完整语法是:
Create {Database | Schema} ‘Filespec'
[User ‘Username' [Password ‘Password']]
[Page_Size [=] Int]
[Length [=] Int [Page[S]]]
[Default Character Set Charset]
[ <Secondary_File>];
<Secondary_File> = File ‘Filespec' [<Fileinfo>] [<Secondary_File>]
<Fileinfo> = Length [=] Int [Page[S]] | Starting [At [Page]] Int
[ <Fileinfo>]
说明:
1、'Filespec'是数据库文件名,包括了存储设备名、路径名、数据库名。缺省情况下,数据库是按照单一文件创建的,这个文件称为主要文件
(Primary File)。从InterBase6.5版本开始就允许创建超过4G的单一数据库。例如:
Set Sql Dialect 3;/*设定Dialect=3*/
Set Names None;
Create Database 'D:\Yqh\Dbdemo1.ib';
2、Length参数是指定数据库文件的长度,单位是页。随着使用数据库增长超过了指定的长度,InterBase会自动扩展数据库文件的大小,在多文件
数据库下则会将数据存储到其它文件中。
3、starting at 选项让你指定下一个辅助文件的起始页码。InterBase总是把最后一个文件作为动态变化长度对待的,也就是说,InterBase在
需要时自动扩展最后一个文件的长度以扩展数据库的容量,主要文件和其他辅助文件均保持LENGTH指定的长度不变,这也意味着,为最后一个
辅助文件或者单一文件数据库的主要文件指定LENGTH长度是没有意义的,因为它们总是动态变化的。
4、InterBase缺省的数据库页面大小为1024字节,可以通过page_size选项将其变为其它大小。增加页面大小的好处有:
—索引工作速度加快,因为索引需要维护的树深度变浅了。
—页面增大后可以在单个页面上能存储更大的记录,这样可有效的提高性能。
—当blob类型的数据能存放在单个页面上时,其存取效率明显加快。
页面的大小必须大于最大记录的大小。

创建数据库影像是InterBase的一个重要的优秀特性。当发生存储介质错误、网络错误或者意外删除数据库的情况下,InterBase7.0可让你恢复
数据库。数据库的影像就是数据库的另一份物理拷贝,一旦给数据库定义了影像,那么数据库的任何变化都被同步地写到影像中,从而使影像
与数据库始终保持数据和状态的高度一致。影像的好处是:
—数据库恢复很快。
—创建影像并不需要独占数据库。
—控制存储空间的分布。数据库影像可以跨越多个设备多个文件。
—影像操作并不需要单独的进程处理。它由数据库的进程句柄负责处理。
—影像在幕后工作,需要很少或几乎不需要任何维护。
创建影像的语法是:
Create Shadow Set_Num [Auto|Manul] [Conditional]
‘Filespec’ [Length [=] Int [Page[S]]] [Secondary_File];
其中:
<Secondary_File>= File ‘Filespec’ [<Fileinfo>] [Seconary_File]
<Fileinfo>={Length[=]Int [Page[S]]| Starting [At [Page]] Int}
[ <Fileinfo>]
说明:Set_Num是影像集合标识,它告诉InterBase语句中列出的所有的影像文件均被组织在该标识之下,影像文件的扩展名是.shd。另外,
该语句创建的的影像总是你正在连接的当前数据库的影像。影像文件的名字并不能代表它是哪个数据库的影像,但是使用数据库的名字给影
像文件命名,便于理解、查看和管理。Auto|Manul是自动模式和手工模式,和数据库一样,影像也可能因为磁盘错误、网络错误及意外事故
而导致失败。如果数据库影像是以自动模式创建的,那么当影像失败时数据库可以继续正常运行。否则,如果影像是以手工模式创建的,那
么数据库访问就会被拒绝,直到数据库管理员进行处理。因此,可以看出自动模式和手工模式的优缺点是:自动模式当影像失败时不影响主
数据库的操作,但是数据库管理员可能不知道数据库目前已经影像失败;手工模式当影像失败时中止对主数据库的操作,需要数据库管理员
的干预。选择何种模式与你的实际要求相关。如果一些关键性业务数据库的恢复在你的系统中比较重要,你最好以手工方式建立影像,以确
保数据库时刻被正确影像。自动模式是InterBase默认的。条件影像是指当数据库的影像升级变为主数据库时,会自动地为该数据库创建一个
新影像文件使得数据库影像不被中断。条件影像是以关键词Conditional来表示的,使用Conditional语法可以使InterBase在下列两种情况下
自动地创建新的影像:
—当数据库或者其影像文件之一无效时
—因硬件错误导致影像接替数据库升级成为主数据库时
删除影像的语法是:
Drop Shadow Set_Num;
该语句既删除了影像引用又删除了物理影像文件。

想查看数据库的有关信息就要用到SQL语句:SHOW DATABASE。
Containing, starting with,,like等运算符则对整数数据进行字符方式的比较。
InterBase7.0支持两种定点数字类型:numeric和decimal。这两种类型的格式是:numeric[(p[,s])] 、decimal[(p[,s])]。其中:p为精度,
也就是数字的总长度,范围从1到18;s为标度,指小数点后的位数,范围从0到p。

InterBase将BLOB数据存储在数据库中,BLOB列只存储BLOB ID,不存储BLOB实际数据,BLOB实际数据存储在数据库的BLOB页面上。BLOB ID像
指针一样指向BLOB数据。BLOB通常被组织成多个同一尺寸的段的集合,即以段为单位顺序存放数据。 对BLOB数据的读写,也是按段为单位进
行的。段的缺省大小为80字节,最好的情况是把段的大小定义为和数据页的大小一致,这样可获得最好的访问性能。指定段的大小用
segment size语法。例如下面的表创建了两个BLOB列:
Create Table Table2(Blob1 Blob,Blob2 Blob Segment Size 512);
在定义BLOB数据时,可以进一步指明其子类型。子类型是用s _type子句和一个正数或负数表示的。正数是系统保留使用的,所有的用户自定
义子类型必须用负数表示。下面的表格说明了InterBase保留的子类型:
----------------------------------------------
子类型 描述
----------------------------------------------
0 无结构和无类型二进制数据
1 文本数据
2 二进制语言表示(BLR)
3 访问控制列表
4 预留
5 数据表当前元数据的编码描述
6 对不规则结束的多数据库事务的描述
---------------------------------------------
最常用的子类型是0、1。
例如:
Create Table Table2(Blob1 Blob,Blob2 Blob S _Type 1,Blob3 Blob S _Type -1);
上面的语句创建了一个含有三个BLOB类型的数据表。第一个是缺省子类型0,代表无类型二进制数据;第二个子类型为1,代表是文本数据;
第三个子类行为-1,代表用户自定义类型。

BLOB的子类型是和BLOB的过滤器一起工作的。BLOB过滤器就是能将BLOB数据从一个子类型转换为另一个子类型的一些程序。InterBase7.0
包含一系列内部过滤器,这些过滤器能将子类型0转换为子类型1,也能将InterBase的系统子类型转换为子类型1。你可以编写自己的过滤
器以实现其它功能,比如将图像从一种格式转换为另一种格式。已经有一些第三方开发的功能各异的BLOB过滤器,你可以到网上去查询下载。
每一个BLOB过滤器都和一对整数值关联,他们分别代表输入和输出子类型。当定义读写游标时,通过FROM 和TO指定相应的过滤器。InterBase
也正是基于FROM和TO来激活过滤器工作的。特别需要指出的是:netware服务器不支持BLOB过滤器。

数组类型的字段,例如:
Create Table Table1(Int_Arr2 Integer[4,5],Int_Arr3 Integer[4,5,6],Int_Arr6 Integer[4,5,6,7]);
上面的例子分别定义了三个数组的列,第一个是2维数组,4行5列,共存储20个元素;第二个是3维数组,共存储120个元素;第三个是4维数
组,共存储840个元素。
默认情况下,数组的下界是从1开始的。例如:
Create Table Table1(Int_Arr Integer[4]);
INT_ARR数组的下界为1,上界为4。你也可以改变下界的值,格式是:下界:上界。例如:
Create Table Table1(Int_Arr Integer[0:3, 0:3]);
上面的2维数组的下界都从0开始,上界为3。

InterBase7.0提供了cast()函数进行类型转换。cast函数的语法是:
CAST(val AS datatype)
其中:val为要转换的值,datatype是目标类型。

InterBase的域是一个数据库全局对象,相当于其他关系数据库的自定义数据类型。域一旦创建,数据库中的其他对象例如表、列就可以使用
它。使用域,不但可以加强数据的一致性,还可以扩展、丰富InterBase的数据类型。创建域的语法是:
Create Domain Domain_Name [As] <Datatype>
[Default { Literal | Null | User}]
[Not Null] [Check ( <Dom_Search_Condition>)]
[Collate Collation];
其中:Domain_Name是创建的域名,Datatype是域的数据类型。其它为可选项。Collate子句用来为字符类型的列指定一个特定的排序顺序。当
然你选择的排序顺序一定要为列的字符集所支持。另外要注意的是,施加在列上的排序顺序总是覆盖施加在域上的排序顺序。
更改域的语法是:
Alter Domain Name {
[Set Default { Literal | Null | User}]
| [Drop Default]
| [Add [Constraint] Check ( <Dom_Search_Condition>)]
| [Drop Constraint]
| to New_Domain_Name
| Type Data_Type
};

计算字段,比如,下面的例子基于first_name和last_name创建了一个计算字段full_name。
Create Table Employee
(First_Name Varchar(10) Not Null,
Last_Name Varchar(15) Not Null,
Full_Name Computed By (Last_Name || ', ' || First_Name));
在域上使用检查约束必须使用关键字val代表将来与该域绑定的列值,而在列上使用检查约束则不需要此关键字,直接使用列名。
创建检查约束的语法是:
CHECK ( <search_condition>);
<search_condition> ={<val> <operator>{ <val>
|(<select_one>)}
| <val> [NOT] BETWEEN <val> AND <val>
| <val> [NOT] LIKE <val> [ESCAPE <val>]
| <val> [NOT] IN ( <val> [ , <val> ...] | <select_list>)
| <val> IS [NOT] NULL
| <val> {[NOT]{=|<|>}|>=|<=}
{ALL |SOME |ANY}(<select_list>)
| EXISTS ( <select_expr>)
| SINGULAR ( <select_expr>)
| <val> [NOT] CONTAINING <val>
| <val> [NOT] STARTING [WITH] <val>
|(<search_condition>)
|NOT<search_condition>
| <search_condition> OR <search_condition>
| <search_condition> AND <search_condition>}
<Operator> ={=|<|>|<=|>=|!<|!>|<>|!=}

通常情况下,你创建的所有数据表都将存储在InterBase的数据库中。但InterBase也允许你创建不存储在InterBase数据库中的表,这样的表
称为外部表, 它以ASCII格式存储数据。外部表最大的优点是允许其它非InterBase应用也可以访问操作数据表。创建外部表的方法是在
Create Table中使用EXTERNAL [FILE] ' filespec'子句。InterBase7.0以前的版本中,对外部表的存储位置没有严格的限制,在InterBase7.0
中,严格规定了外部表存储的位置,以增强安全性,默认的存放位置是InterBase安装目录下的ext子目录。如果你想放在其它目录,就必须在
配置文件中通过EXTERNAL_FILE_DIRECTORY参数指定存放外部表的位置。

出于某种需要你可能要改变列在表中的位置,Alter Table语句中的选项Position可以完成这个功能。例如:
create table mytbl(col1 integer,col2 integer,col3 char(4));
我们想把col3移到第二个位置,做法如下:
Alter Table mytbl Alter col3 Position 2;
这样,col3就和col2位置互换了。

索引按其结构可以分为聚集索引(Clustered Index)和非聚集索引(Non-clustered Index)。在InterBase中,如果你定义了主键,那么主键
上的索引就是聚集索引。一个表只能有一个聚集索引。其他索引都是非聚集索引,非聚集索引可以有多个。聚集索引最适合范围搜索和多行搜索;
而非聚集索引适合于单行搜索。
索引极大的加快了查询的速度,这是其最大的优点。但是使用索引会额外消耗存储空间,并且由于每当列中的值发生变化或者增加、删除了数
据行时必须更新索引,所以在建立了索引的列上执行insert,update,delete操作要比非索引列耗费更长的时间。下面的情形可以使用索引:
—经常被where查询条件引用的列可以使用索引。
—join联合条件中经常引用的列可以使用索引。
—order by子句经常用来排序数据的列可以使用索引。
而下面的情形最好不要使用索引:
—where查询条件很少用的列。
—经常会被更新的非关键字段列。
—只有少量可能值的列(如性别:男/女)。
—行数很少的的小表一般也没有必要创建索引。
Create Index语句可以在一个或多个列上创建索引。语法是:
CREATE [UNIQ] [ASC | DESC] INDEX index_name ON table_name ( col [, col ...]);
注意:InterBase为主键、外键列自动创建唯一索引。在下列情况下InterBase会使用复合索引中的一部分来优化查询:
—如果where或order by子句中使用的列中的第一个列正好是复合索引中的第一个列。例如,假设复合索引列是a1,a2,a3,查询使用了a1,a2,
  那么该查  询可以被优化;如果查询使用的是a2,a3,就不会进行优化。
—如果where或order by子句中列的顺序正好和复合索引的列顺序一致。
如果你经常在查询中使用or操作符,最好为条件中的列创建一个单独的索引,这样可加快速度。
优化索引性能:
数据库使用时间长了,由于数据的多次更新,原先的索引可能就会变得不平衡了。这时,就要进行索引的优化,大致方法如下:
—使用alter index重建索引,先使用alter index index_name inactive关闭索引,再使用alter index index_name active启用索引。
—如果数据表中索引字段的重复值增减的幅度相当大,就可以使用set statistics index index_name重新计算索引。
—使用drop index删除索引,并用create index重建索引
—使用gbak备份并恢复数据库
—索引的性能还与数据页面的大小密切相关。

InterBase的Select语句的完整语法是:
Select [Transaction transaction]
[Distinct|All]
{*|<val>[,<val>…]}
[Into :var[,:var…]]
From <tableref>[,<tableref>…]
[Where <search_condition>]
[Group By col [Collate collation][,col [Collate collation]…]
[Having <search_condition>]
[Union [All] <select_expr>]
[Plan <plan_expr>]
[Order By <order_list>]
[Rows <val> [To <upper_val>][By <step_val> [Percent][With Ties]]
[For Update [Of col[,col..]]];

生成器是一种数据库对象,其主要作用就是产生一个不重复的序列值。而且每使用一次,序列值就会在原来值的基础上自动增加,增加的幅度
由步长来控制。一个数据库中可以定义多个生成器,生成器在数据库中为全局对象。生成器通过Create Generator创建。语法是:
CREATE GENERATOR gen_name;
刚创建的生成器其初值默认为0。要删除生成器,只能到InterBase系统表中操作,例如:
DELETE FROM RDB$GENERATORS WHERE RDB$GENERATORS_NAME = ‘My_Gen’;
将删除生成器My_Gen。
使用SET GENERATOR gen_name TO int_val可以改变生成器的初值。生成器被创建之后,就可以通过调用Gen_Id(gen_name,step)函数来让它
工作,这个函数返回一个64位的整数。

异常是InterBase数据库的一种全局性对象,实际上,异常是一个特别命名的用户自定义消息,当异常被激发时,它将这个自定义的消息返回给
调用它的程序。通常,异常在存储过程和触发器中使用。当在存储过程或触发器中激发异常时,如果没有WHEN语句对异常进行处理,那么异常
除了给出消息外,还将终止存储过程或触发器的执行,并回退存储过程或触发器所在的事务。要创建异常,使用下面的语法:
CREATE EXCEPTION Exp_name ' <message>';
其中,Exp_name是异常对象的名称,message是该异常对象给出的具有实际意义的特定信息。例如:
Create exception New_Customer '新客户添加失败!';
在存储过程和触发器中使用异常的方法是:
exception exception_name;

·上下文变量old,new是触发器特有的,存储过程编写中不能使用他们。
·输入参数、输出参数、suspend、exit等是存储过程特有的,不能用在触发器的编写中。
nterBase存储过程触发器中不包括SQL数据定义语句DDL和内嵌事务处理语句。

InterBase的存储过程分为两大类:
一类是选择式存储过程,它返回一个数据集,客户端使用select语句调用存储过程,此时存储过程的作用好像和表、视图一样,选择式存储过
程必须通过输出参数返回一个或多个数据行。另一类是执行式存储过程,它不返回数据集,客户端使用execute procedure来调用存储过程,
这类存储过程大多数只执行一些动作而不返回数据行,当然它也可以返回输出参数信息。
注意:InterBase不存在这样的存储过程,它既返回数据集,同时又返回非数据集的输出参数,你只能选择其一。如果用select语句调用存储过
程,select语句中的列名以及数据类型必须和存储过程的输出参数的名称及数据类型匹配;如果用execute procedure调用,列名称可以不匹配,
但数据类型必须与输出参数的数据类型匹配。不论是输入参数、输出参数还是局部变量,如果在SQL语句中使用,前面必须加上冒号。如果不和
SQL语句一起使用,则不要加冒号。

创建存储过程的语法是:
CREATE PROCEDURE procedurename [( param datatype [, param datatype …])] /*输入参数据列表*/
  [RETURNS ( param datatype [, param datatype …])] /*输出参数列表*/
AS
  [DECLARE VARIABLE var datatype;         /*局部变量定义*/
  [DECLARE VARIABLE var datatype; …]]
BEGIN
  < compound_statement>
  [< compound_statement>…]
END
其中:CREATE PROCEDURE和AS之间的部分称为存储过程的头部。procedurename是存储过程的名字;AS之后的部分是存储过程的主体。
BEGIN和END之间的body of procedure是存储过程的主要部分,这里是编写存储过程全部代码以及商业逻辑的地方。
*************************************************************
注意:在存储过程中,除了Create Procedure,As,Begin…End语句之外,任何其他语句末尾都要添加分号结束。因此,如果你使用isql创建存
储过程,你必须另外定义其它的符号来代表创建存储过程的结束,通常使用set term语句完成。比如:
Set Term ## ;
Create Procedure Add_Emp_Proj (Emp_No Smallint, Proj_Id Char(5))
As
Begin
Begin
Insert Into Employee_Project (Emp_No, Proj_Id)
Vals (:Emp_No, :Proj_Id);
When Sqlcode -530 Do
Exception Unknown_Emp_Id;
End
Return;
End ##
Set Term ; ##
************************************************************

注意:所有的BEGIN,END之后均不能带分号,除此之外所有的语句必须以分号结束。
赋值语句:variable=expression;
注释:/*…..*/

******************************************************************************************
存储过程的例子:
Create Procedure Factorial (Num Int)
  Returns (N_Factorial Do le Precision)
As
  Declare Variable Num_Less_One Int; /* 局部变量的定义格式为:delclare variable 变量名 类型名; */
Begin
  If (Num = 1) Then
  Begin /**** Base Case: 1 Factorial Is 1 ****/
    N_Factorial = 1;
    Exit; /* exit的作用:跳到存储过程的最后一个END语句,结束存储过程的执行。*/
  End
  Else Begin
    /* 以下的语句是一个递归调用:Num Factorial = Num * (Num-1) Factorial */
    Num_Less_One = Num - 1;
    Execute Procedure Factorial Num_Less_One Returning_Vals N_Factorial; /* 执行存储过程的格式为:execute procedure 存储过程名 输入参数列表 returning_vals 输出参数列表; */
    N_Factorial = N_Factorial * Num;
    Exit;
  End
End
******************************************************************************************

单行选择语句Select…Into:将选择的结果存储到Into之后的变量中,into子句必须放在整个选择语句的末尾。例如:
Select Count(*) from Employee Into :varcount;

返回多个数据行。语法结构是:
For select_statement
Do
Compound_statement
例如,下面的存储过程返回多个数据行,并且实现了其它数据库的SELECT TOP-N …的功能:
CREATE PROCEDURE SP_Select_TopN_Orders(WhichCust INTEGER, HowMany SMALLINT )
  RETURNS( WhichOrd INTEGER, WhenSold DATE, HowBig FLOAT)
AS
  DECLARE VARIABLE i SMALLINT;
BEGIN
  i = 0;/*局部变量,控制返回的数据行数*/
  FOR SELECT OrderID, SaleDate, TotalInvoice
      FROM Orders
      WHERE CustomerID = :WhichCust
      ORDER BY TotalInvoice DESC
      INTO :WhichOrd, :WhenSold, :HowBig/*提取信息到输出参数中*/
  DO BEGIN
    SUSPEND;/*返回输出参数*/
    i = i + 1;/*行数加1*/
    IF ( i = :HowMany ) THEN
      EXIT;/*达到规定的行数退出*/
  END
END

条件语句:
IF (condition) THEN compound_statement
[ELSE compound_statement]
说明::condition为布尔表达式(真、假或未知),必须放在括号中,它可能的情况如下:
=、>、<、>=、<=、<>、between and、like、in、is [not] null、containing、starting with。

POST_EVENT event_name:
用来发送一个事件。事件是InterBase一种异步消息机制,通过事件可以向客户端返回需要的信息。其他关系数据库的存储过程和触发器语言
一般都有一个Print语句用来把信息返回给客户端,Post_Event就类似这个Print的功能,只是事件的发送是异步的。当然要使用事件,客户端
要注册到InterBase的事件管理器,以便接收所需的消息。如IBX就可以很好地实现这个功能。
事件是由存储过程、触发器传递给事件管理器的一个消息,用来表明某个特定的条件或动作发生了,比如insert,update,delete。事件管理维
护着一系列事件的列表,同时也维护着对特定事件感兴趣而注册的应用程序列表。事件在存储过程或触发器的事务提交时由POST_EVENT传递给
事件管理器,然后由事件管理器发送给注册该事件的应用程序。

SUSPEND:
暂时终止即挂起存储过程的执行,并将参数返回给客户端。这是存储过程专用的语句。

WHILE condition DO compound_statement:
当condition条件为真时,重复执行compounde_statement语句,直到condition条件为假时退出。

WHEN {error[,error…]|ANY} DO compound_statement:
错误处理语句。当指定的错误之一出现时,执行compound_statement语句。如果使用了WHEN,那么必须将其放在整个存储过程或触发器的最
后一个语句。error可以是异常、SQLCODE错误码、GDSCODE代码。ANY表示处理任何错误。

END语句在选择式存储过程中,表示存储过程执行完毕,将控制权返给调用程序,并将SQLCODE设置为100,表示再也没有数据行可提取了;
END在执行式存储过程中,表明存储过程执行结束,将控制权交给调用程序,如果有输出参数的话,同时将输出参数传递给调用程序。

考虑下面的存储过程:
Create Procedure P Returns (R Integer)
As
Begin
  R =0;
  While (R <5)Do
  Begin
    R =R +1;
    Suspend;
    If(R =3)Then
    exit;
  End
End
如果作为选择式存储过程使用select * from p调用,将得到1,2,3三个值。因为每次循环遇到SUSPEND语句,将输出参数R传递给调用程序,
直到R等于3为止;如果作为执行式存储过程使用execute procedure p来调用,你只能得到1一个值,因为在执行式存储过程中,SUSPEND语句
直接将流程转到最后一个END上,最后的END语句结束存储过程的执行,并将输出参数传出。

使用选择式存储过程的语法是:
SELECT < col_list> from name ([ param [, param …]])
WHERE < search_condition>
ORDER BY < order_list>;

使用执行式存储过程的语法是:
EXECUTE PROCEDURE name [(] [ param [, param …]] [)];
这里需要说明的是执行式存储过程的输出参数。如果你在isql中使用Execute Procedure执行,无需指定返回参数,输出参数自动显示在屏幕
上。如果你使用DELPHI的语言编程执行,那么可以通过存储过程控件获取输出参数。如果你在其它存储过程中调用,可以通过
RETURNING_VALS获取输出参数值。

通过存储过程访问表的数组字段:
  不能使用简单的select语句来显示数组字段的内容,因为只有数组的ID存储在字段中。可以编写存储过程来显示数组字段的内容。
例如employee.ib样本数据库中的job数据表就有一个数组字段lang ge_req,它的类型为LANG GE_REQ VARCHAR(15) [1:5] CHARACTER SET NONE,
可以使用如下的存储过程显示其内容:
Create Procedure View_Langs
  Returns (Code Varchar(5), Grade Smallint, Cty Varchar(15),Lang Varchar(15))
As
  Declare Variable I Integer;
Begin
  For Select Job_Code, Job_Grade, Job_Country
      From Job
      Where Lang ge_Req Is Not Null
      Into :Code, :Grade, :Cty
  Do Begin
    I =1;
    While (I <=5)Do
    Begin
      Select Lang ge_Req[:I] From Job
      Where ((Job_Code = :Code) And (Job_Grade = :Grade)
            And (Job_Country = :Cty)) Into :Lang;
      I =I +1;
      Suspend;
    End
  End
End

在存储过程中激发异常,使用EXCEPTION exception_name;
当异常激发时,如果没有When…Do对之进行处理,它将:
·终止存储过程的执行,撤销存储过程所做的一切动作,包括直接的和间接的。
·向调用存储过程的程序返回异常定义的逻辑错误信息。
可见,异常特别适合用在根据一定的条件终止操作的执行并回退的情况,因此,对于实现商业逻辑具有十分重要的意义。
使用WHEN…DO语句可以处理三种类型的错误:
·逻辑错误异常。包括存储过程或触发器中激发的异常。
·SQLCODE报告的SQL错误。
·GDSCODE报告的InterBase错误。
使用WHEN…DO进行错误处理的语法是:
WHEN {< error>[,<error>…]|ANY}
DO <compound_statement>
< error>=
{EXCEPTION exception_name | SQLCODE number | GDSCODE errcode}
当异常激发后,InterBase如何处理:
·查找一个处理异常的WHEN语句。如果没有找到这样一个语句,就终止包含异常的BEGIN…END语句块的执行,并且撤销该语句块所做的一切动作。
·跳到包含异常的BEGIN…END语句块的外层语句块中查找有无处理异常的WHEN语句,如果没有,继续向外层跳,直到找到一个为止。如果最终没有找一个可以处理异常的WHEN语句,就终止该异常所在的存储过程或触发器的执行,并撤销该存储过程或触发器所做的一切动作。前面我们讲到的就是这种情况。
·找到WHEN语句后,就执行DO中的语句,对异常作出特定的处理。
·将控制权返回给存储过程或触发器中接着WHEN语句的下一个语句块继续执行。

WHEN…DO语句也可以处理由SQLCODE报告的SQL错误。每当执行完一条SQL语句后,SQLCODE总是包含一个状态码指示该SQL语句执行成功还是失
败。SQLCODE也可以包含一些警告状态信息。

处理InterBase错误的语法是:
WHEN GDSCODE errcode DO <compound_statement>;
例如当一个用户更改一个已经由其他事务更改但尚未提交的数据行时,就会产生一个InterBase错误LOCK_CONFLICT,这种情况下使用WHEN语句捕获处理该错误的模型是:
WHEN GDSCODE LOCK_CONFLICT DO <compound_statement>;

创建触发器的语法如下:
CREATE TRIGGER name FOR { table | view}
  [ACTIVE | INACTIVE] {BEFORE | AFTER} {DELETE | INSERT | UPDATE}
  [POSITION number]
AS
  [DECLARE VARIABLE variable datatype;[DECLARE VARIABLE variable datatype;…]]
BEGIN
  < compound_statement>[<compound_statement>…]
END
说明:
name:触发器的名称,必须是唯一的。
table:当特定的动作发生时引起触发器触发的数据表或视图,或者说欲将触发器定义在其上的表或视图。
ACTIVE|INACTIVE:可选项ACTIVE是默认的动作,表示为活动状态即触发器起作用。INACTIVE表示非活动状态,即不起作用。
BEFORE|AFTER:指定触发器触发的时间。BEFORE表示在相应的动作之前触发。AFTER表示在相应的动作之后触发。这些动作指INSERT、DELETE、UPDATE。
INSERT|DELETE|UPDATE:表示引起触发器触发的数据表操作。
POSITION number:当有多个相同类型的触发器时,指定他们的触发顺序。范围在0到32767之间。号码小的先触发。默认值为0代表第一个被触发。
New、Old两个触发器特有的上下文变量分别代表触发器被触发时新数据和旧数据。它们的用法为:NEW. column,OLD. Column。
注意:NEW和OLD变量前面不要加冒号,即便它们和SQL语句一起连用也是如此。NEW变量的值只能在INSERT、UPDATE动作之前更改,在之后更改
是不允许的;数据列的实际值只有在INSEERT、UPDATE动作之后才真正更新到数据库,因此只有在AFTER INSERT、AFTER UPDATE触发器中才能
看到刚插入或更新到数据库的新列值。

触发器可用在下列多种不同的场合提供强大的功能。
·更新相关数据表,比如为数据库或数据表维持一个日志文件。
·强制数据约束,确保只有有效的数据才可以进入数据表。
·自动数据转换,例如把小写字符转换为大写字符。
·通过InterBase的事件机理进行异步消息处理。
·执行级联引用完整性更新。
例如:
·before delete触发器可以在删除时检查主要明细表之间的关系,也可以终止删除。
·所有的before触发器均可以通过激发异常终止操作回退事务。
触发器是在引起触发器的事务中操作的,触发器所有的动作被看作是该事务的一部分,如果该事务回退,那么触发器所做的一切动作都将被回退。
触发器一个很重要的用途就是作为事件报警器,当数据库发生变化时,激活触发器向用户发出通知。例如,你可以为客户表创建一个After Insert触发器,每当插入一个新客户后就向用户报告:
Create Trigger Post_New_Customer For Customers After Insert As
Begin
Post_Event ‘New_Customer_Insert_S?!’;
End

在InterBase中,如果你没有控制事务,那么每一个SQL语句都会自动启动一个事务,即InterBase工作在自动事务模式。InterBase不支持内
嵌事务处理,根本不存在进行事务处理的语句。你不可能像MSSQLServer等数据库一样,在存储过程和触发器中通过begin trans(action),
commit trans(action),rollback trans(action)等语句进行事务处理。在InterBase中,所有的事务,不论是显式的还是隐式的,全部通过客
户端启动,并根据客户端操作的情况要么提交要么回退。当客户端发起一个sql请求时,同时也启动一个事务,如果该语句执行成功,
InterBase就自动提交该事务;否则,如果该语句执行失败,InterBase就回退事务。一个sql语句的执行可能会嵌套调用或引发其他sql语句的
执行,这些sql语句也会启动各自的事务,我们把第一个被启动的事务称为根事务,其他事务称作子事务。这样,根事务、子事务就形成了一
个具有嵌套结构的事务链。只有当该事务链中所有环节对应的操作全部执行成功(不能有任何一个失败),InterBase才提交事务;相反,只
要事务链中任意一个环节对应的操作失败(尽管其它环节操作成功),InterBase就回退全部事务。InterBase决不会进行部分事务的提交。
在客户端调用存储过程或执行插入、更新、删除操作时触发了触发器,都会启动一个根事务,而存储过程或触发器中的SQL语句了会启动子事务,
这样就形成事务链。所以如果在存储过程或触发器中出现操作错误,都会回退事个事务链,包括触发触发器的所有操作。
如果你使用delphi的IBX编写客户端,你可以通过TIBTransaction的starttransaction,commit(或commitretaining),rollback
(或rollbackretaining)选择合适的时机明确地启动、提交、回退事务。但是,一定要遵守一个原则,即:事务期间要尽可能地短。

InterBase有如下内置函数:
1、AVG([ALL] val|DISTINCT val):平均值函数,它返回指定列或表达式的平均值。
2、CAST(val AS datatype):类型转换函数,可以将一个列的值从一个数据类型转换为另一个数据类型。
3、COUNT(*|[ALL] val|DISTINCT val):返回满足条件的查询的行数。
4、EXTRACT(part FROM val):从DATE、TIME、TIMESTAMP类型的值中抽取出日期和时间信息。其中:part是指YEAR、MONTH、DAY、HOUR、MINUTE、SECOND、WEEKDAY、YEARDAY等日期时间信息,val是指DATE、TIME、TIMESTAMP等类型的值。
5、GEN_ID(generator,step):返回系统产生的一个整数值。其中:generator是生成器的名字,step是增长的步长。
6、MAX([all] <val>|DISTINCT <val>):返回列的最大值。
7、MIN([ALL] <val>|DISTINCT <val>):返回列的最小值。
8、SUM([ALL] <val>|DISTINCT <val>):返回一个列的总和。
9、UPPER(<val>):将字符串全部转换为大写。

用户自定义函数就是根据用户实际应用的需要而自行开发的函数。用户自定义函数和InterBase中内置的函数一样,可以用在任何需要使用函数
的地方。用户自定义函数是对InterBase Server功能的扩展,并作为InterBase Server进程的一部分执行,它的能力几乎是无限的。

通常?是以动态链接库的形式提供的,要使用?,必须确保?动态链接库存在并且放置在规定的目录中,如InterBase安装目录下的?子目
录。你的数据库要使用?动态链接库中的哪个函数,就必须进行声明,对每个数据库函数只需声明一次即可,声明语法如下:
DECLARE EXTERNAL FUNCTION name [ datatype | CSTRING (int) [, datatype | CSTRING ( int) ...]]
  RETURNS { datatype [BY VAL] | CSTRING (int)} 
  [FREE_IT][RETURNS PARAMETER n]
  ENTRY_POINT ' entryname'
  MODULE_NAME ' modulename';
其中:
name是指你要在SQL语句中使用的函数的名称,紧跟在其后的是函数的输入参数及其数据类型。
datatype指输入或输出参数的数据类型,不能使用数组类型,此外,所有的输入参数都是引用传递的,返回参数可以是值传递的。
RETURNS指明了函数的返回参数及其数据类型。BY VAL表明返回参数应当使用值传递而不是引用传递。CSTRING (int)表明函数返回若干个字节的空结束字串。FREE_IT当?运行结束后释放其返回值动态分配的内存空间。
RETURNS PARAMETER n表明函数返回第n个输入参数,当返回blobs时需要。
Entryname是函数在?库中的函数名字
Modulename是包含?的动态链接库名称。
nterBase安装后,默认在?子目录下安装了一个?的动态链接库,名字是ib_?.dll,该动态库包含了常用的数学和字符运算函数。要使用
ib_?.dll这个?,我们只需要运行examples\?目录下的ib_?.sql脚本即可,该脚本包含了库中全部的函数声明。例如其中的一个函数
声明语句如下:
DECLARE EXTERNAL FUNCTION sqrt DO LE PRECISION
  RETURNS DO LE PRECISION BY VAL
  ENTRY_POINT 'IB_?_sqrt' MODULE_NAME 'ib_?';


InterBase在逻辑上可分为四大模块,分别是:远程通信模块、SQL语法解析器、数据库引擎、锁管理器。各个模块的作用是:
1、远程通信模块:该模块允许客户端通过远程或者本地连接到数据库。
2、SQL语法解析器:将SQL请求翻译为数据库本地语言BLR。
3、数据库引擎:是InterBase数据库系统的核心,执行实际的请求。
4、锁管理器:处理事务间的同步。
InterBase 数据库的所有内容(对象、数据、事务日志)全部放在一个文件(即数据库文件)中。

InterBase 在运行时需要动态地创建两个临时文件:排序文件和历史列表文件。
排序文件:当 InterBase 内部的排序缓冲区大小不足以执行排序操作时, InterBase 数据库引擎就会动态地创建临时排序文件。排序操作完
成后, InterBase 引擎会自动释放掉该文件。要确保有足够的磁盘空间供排序文件使用。InterBase 使用的临时空间可能要比数据库本身大
很多,临时排序文件一般位于数据库所在的服务器上,应该在服务器的本磁盘上指定临时目录,而不能在映射驱动器或网络磁盘上创建临时排
序文件。有两种方法为排序文件指定目录:
1、在 InterBase 配置文件(Windows平台下为IBConfig,unix平台下为$interbase/isc_config) 中使用 TMP_DIRECTORY ,语法是:
TMP_DIRECTORY 估计 路径名称。如:
TMP_DIRECTORY 5000000 c:\dir1
TMP_DIRECTORY 8000000 d:\dir2\tmp
可以添加多个临时目录。
2、使用 INTERBASE_TMP 或 TMP 环境变量添加临时目录。
它们之间的优先顺序是:
配置文件 >INTERBASE_TMP> TMP>c:\tmp(Windows) 或/tmp(unix)
历史列表文件: InterBase ISQL 客户端会动态地创建历史列表文件以跟踪输入的命令。每个连接的 ISQL 实例均会创建自己的历史列表文件。
文件大小会自动增加直到无可用的磁盘空间可用为止。当客户端退出连接后,历史列表文件就被自动释放。在客户端机器上使用 TMP 环境变
量定位历史列表文件。如果不指定,Windows平台下将使用 c:\temp , unix 平台下使用/tmp 。

InterBase的多代结构和版本事务
所谓多代结构,就是指每当记录被更改或删除时,InterBase便会自动创建该记录的一个拷贝,这个拷贝就好像是原来记录的下一代一样,和
其它的数据库系统不同,在InterBase中,原来的记录并没有从数据库中清除掉,而是仍然保留在数据库中,于是随着不断的操作,一条记录
可能就会出现多个子代,这就是多代结构。

锁是控制并发访问的最常见的方法。当一个用户要访问数据库中的某个对象时,他就在该数据库对象上加锁,限制其它用户对该对象的访问。
当他访问结束,将加在数据库对象上的锁解除,其他用户就可以访问该对象了。因此锁可以消除用户之间的竞争,保证数据的一致性。一般关
系数据库系统中,锁分为共享锁、排它锁、更新锁。所谓锁的粒度是指一个锁所能限制影响的范围。有行锁、页锁和表锁,行锁的并发性最好,
页锁的并发性最差。从另一个角度还可将锁分为悲观锁和乐观锁。在悲观锁情形下,要更改的对象在开始更改之前就被锁定,而且一直处于锁
定状态,直到提交了对它的更改。在乐观锁情形下,当用户读取一个对象开始更改时并不对它加锁,只有当用户要提交更改时才将该对象锁定。
悲观的缺点是并发访问性不好。乐观锁的缺点是会增加并发用户读取对象的次数。使用乐观的页锁是比较好的。

环境变量和临时文件:
1、ISC_USER和ISC_PASSWORD环境变量:如果你连接数据库或者使用诸如gbak、gstat、gfix等工具时没有提供用户名和密码,InterBase就会查看这两个环境变量是否已经设置了。若设置了,就直接使用它们作为InterBase用户。要小心地使用上述两个变量,因为它们可能带来安全隐患。
2、InterBase环境变量:共5个
INTERBASE:INTERBASE这个环境变量在安装和运行InterBase期间都需要。在安装期间它定义了InterBase安装的路径;在运行期间靠它提供InterBase的安装目录。
INTERBASE_TMP:用来设置InterBase服务器上排序文件的位置。
INTERBASE_LOCK:设置InterBase Lock File的位置。InterBase安装后会在安装目录下生成一个以机器名命名的资源锁文件xxx.lck,
INTERBASE_MSG:用来指向InterBase的消息文件interbase.msg
TMP:如果INTERBASE_TMP没有定义,则使用TMP指明InterBase临时文件的位置。
3、临时文件:InterBase运行时会创建两个临时文件,历史文件和排序文件。对历史文件,可以通过在客户端机器上设置TMP环境变量来指定历史文件的位置。如果没有设置TMP变量,则使用系统的临时目录,例如在Windows下可能为temp目录。有三种方法指定排序文件的目录,分别是TMP_DIRECTORY变量、INTERBASE_TMP变量和TMP变量,并且优先顺序依次递减。

InterBase安装后,在安装目录下有一个重要的系统配置文件ibconfig,这个文件中存放着InterBase Server引擎需要的众多配置参数,每个参数的格式是:参数名 参数值。注意配置文件中每一行的长度限制在80个字符。下面我们把各个参数分别介绍如下:
1)  ADMIN_DB:当InterBase的安全数据库不是admin.ib时该参数才起作用,此时该参数用来指明安全数据库的名称。默认值0(安全数据库是admin.ib)。
2)  ANY_EVENT_MEM_SIZE:分配给InterBase的事件管理器的共享内存大小,单位为字节,默认值是32768
3)  ANY_LOCK_MEM_SIZE:分配给锁管理器的共享内存大小,单位为字节,默认值为98304
4)  ANY_LOCK_SEM_COUNT:只用在InterBase的classic结构体系中。
5)  ANY_LOCK_SIGNAL:只用在InterBase的classic结构体系中。
6)  CPU_AFFINITY:只在Windows平台中有用,用来表明SMP下哪个CPU被使用。默认情况是适用所有的CPU。具体配置参见前面的介绍。
7)  CONNECTION_TIMEOUT:等待一个失败的连接结束所需要的时间,默认值是180秒。
8)  DATABASE_CACHE_PAGES:InterBase Server数据库缓存大小,默认是2048个数据页。
9)  DEADLOCK_TIMEOUT:检查死锁前等待的秒数,默认是10秒。
11)DUMMY_PACKET_INTERVAL:InterBase服务发送一个哑包确认silent客户端连接前要等待的时间,默认值是60秒。
12)EXTERNAL_FILE_DIRECTORY:如果外部数据库文件不是放在InterBase安装目录下的ext子目录中,可以在此参数中另外指定存放目录。
13)EXTERNAL_FUNCTION_DIRECTORY:如果?动态库的目录不是默认的InterBase安装目录下的?子目录,用此参数指定另外的目录。
14)LOCK_ACQUIRE_SPINS:
15)LOCK_HASH_SLOTS:
16)MAX_THREADS:允许InterBase同一时间处于活动状态的最大线程数,缺省值是100。
17)SERVER_CLIENT_MAPPING:进程内通信客户端内存映射文件的大小,缺省值是4096字节。
18)SERVER_PRIORITY_CLASS:指明Windows平台下InterBase服务的优先级别,1为低优先级,2为高优先级,默认为1。
19)SERVER_WORKING_SIZE_MAX:InterBase server最大工作空间,仅对windows平台,默认是由操作系统决定。
20)SERVER_WORKING_SIZE_MIN:InterBase server最小工作空间,仅对windows平台,默认是由操作系统决定。
21)SWEEP_Q NTUM:允许垃圾收集线程和数据库清扫线程再将控制权交给工作线程之前工作的最大记录数,默认是10。如果要增加这个值,最好也要同时增加SWEEP_YIELD_TIME的值。
22)SWEEP_YIELD_TIME:数据库清扫线程或垃圾收集线程睡眠的时间数,单位毫秒,默认是1ms,该参数不影响工作线程。如果要增加该参数值,也要增加SWEEP_Q NTUM的值。
23)TMP_DIRECTORY:存储InterBase临时文件的目录和相应的尺寸。缺省是INTERBASE_TMP环境变量的值,如果没有定义这个环境变量,则使用tmp变量值。
24)USER_Q NTUM:允许InterBase的工作线程再将控制权交给其它线程之前工作的最大记录数,缺省是100。所谓工作线程就是运行用户查询的线程。
25)V4_EVENT_MEMSIZE:分配给InterBase事件管理器的共享内存数,默认值是32768,该参数被ANY_EVENT_MEM_SIZE参数值覆盖。

设置页面的填充率:在InterBase的多代结构中,随着数据的更改,同一记录会出现多个不同的版本。通常情况下,存储数据的页面会留出20%
的空间用来存放记录的多个版本,尽量使同一记录放在同一个页面上,也就是说默认情况下InterBase使用80%的页填充率。如果一个系统主要
是读数据为主的,极少有数据的更改,那么可以将页面的填充率设为100%,减少记录的分片,增加一页上存储的数据量。可以使用gbak在数据
库恢复时改变页面填充率,例如:
gbak -c -use_all_space backup_file.ibk database_file.ib

配置数据库缓存:InterBase为当前使用的数据和索引在服务器内存中维持着一个缓存,这个缓存为所有连接到该数据库的客户端共享。缺
省情况下,这个缓存为256个数据页,可以使用gfix -b?rs n db_name为数据库db_name设置n个数据页大小的缓存。

影响Interbase数据库性能的软硬件配置:
1、I/O性能和网络带宽、CPU性能:
主要是I/O性能和网络带宽,其次是CPU性能。
2、对称多处理器SMP的使用:
需要购买相应的许可,并在InterBase配置文件中设置CPU_AFFINITY参数。配置情况如下:
-------------------------------------------------------------------------------------------------------------------
使用的CPU的情况(数字表示第几个CPU)   CPU_AFFINITY值   CPU二进制数组(从左到右每一位分别代表第一个CPU、第二个CPU…)
-------------------------------------------------------------------------------------------------------------------
1         1        …001
2         2        …010
1、2         3        …011
3         4        …100
2、3         6        …110
1、2、3         7        …111
-------------------------------------------------------------------------------------------------------------------
3、内存容量:
运行InterBase内核程序大约需要1500K内存,每个连接用户大约增加28K左右,因此InterBase所用的大致内存数是1500K+28K*用户数。
此外,InterBase要为它连接的每个数据库缓存元数据和数据,用户操作如排序可能也会临时性使用大量内存,再加上多个用户执行并发
查询等种种情况,InterBase可能需要更多的内存,可能多达256M。可以使用相应的工具查看InterBase使用资源的情况,当系统频繁地
出现数据页错误时,极可能就是内存不足造成的。
4、禁止屏幕保护程序。
5、在服务器上,如果控制台不需要了,就要关闭它。
6、临时目录:
InterBase可能要使用2倍于数据库大小的空间执行某些操作如排序等,因此要把临时目录加大并且放在比较空闲的磁盘上。临时目录空间不
足,可能会导致诸如虚拟内存页面错误、I/O错误等。
7、使用专用服务器:
最好把文件服务和打印服务与数据库服务分开,使InterBase运行专用的服务器上。否则,文件和打印服务就会非常明显地影响数据库系统的
性能。

关闭数据库的选项有:
1、关闭超时选项Shutdown timeout:通常其范围为 1~500 分钟。
2、其他关闭选项: 
1)Deny new connections while waiting等待期间拒绝新的数据库连接:该选项允许所有已经存在的数据库连接不受影响地完成其操作任务,
并在所有的操作完成后关闭数据库。如果关闭超时选项规定的时间已到仍然有活动的连接,数据库不被关闭。这个选项在关闭超时选项规定的
时间内阻止任何对数据库的新连接,这样允许当前用户完成其工作,同时阻止其他用户开始新的工作。
2)Deny new transactions while waiting等待期间拒绝新的事务:该选项允许已经存在的事务运行至正常结束,一旦所有事务结束,关闭数
据库。拒绝新的事务意味着同时拒绝新的数据库连接。因此这个选项要比第一个选项严格。当规定的关闭时间到达时,如果仍有活动的事务存
在,数据库不会被关闭。
3)Force shutdown after timeout规定时间到强制关闭数据库:该选项对事务、连接无限制。只要没有活动的进程或连接访问数据库,就关
闭数据库。规定时间到达时,如果仍有活动的连接,回退所有未被提交的事务,断开与数据库的链接,并关闭数据库。
注:在规定的关闭数据库时间到来之前, InterBase 会给用户广播消息通知将关闭数据库,催促用户尽快结束工作。

设置数据库的写入方式:
1、强制写入:
当执行写操作时物理地将数据直接写入磁盘数据库。好处是可保证数据能及时写到数据库,确保数据的一致性和安全性,但是写入速度慢,
影响系统性能。
2、缓存写入:
当执行写操作时,不是直接将数据写入磁盘数据库,而是写到数据缓冲区,当缓冲区满时再将其中的数据物理的写进数据库。速度很快,但
是如果数据未真正写入磁盘之前发生故障,数据将全部丢失。
一般的,当操作系统比较稳定时,使用缓存写入是比较有效的。默认情况下 InterBase 执行强制写入。

数据库清扫:InterBase采用的是多代结构体系,当记录被更改或删除后,会生成多个版本,并不是所有的版本都是有用的,这些无用的版本
存储在数据库中会增加数据库的大小并降低数据库的性能,因此要及时将它们清除去数据库。自动垃圾收集、数据库清扫均可以做这项工作。
1)设置数据库自动清扫间隔:默认情况下,当OIT与OAT的差达到20000个事务时就启动数据库清扫,你可以根据情况改变这个阀值。
2)禁止数据库清扫:如果你把上述间隔值设为0,就禁止了数据库自动清扫。在下列的情况下禁止数据库自动清扫是有好处的,如为获得最大的数据吞吐效率或准备手工安排数据库清扫。
3)立即执行数据库清扫:你也可以直接选择某个数据库,然后立即执行数据库清扫。

Limbo事务处理
当提交一个跨多个数据库的事务时,InterBase会自动执行两阶段提交。两阶段提交确保事务要么更新该事务所涉及的所有数据库,要么一个也
不更新,从而保证所有的数据库永远不会被部分的更新,全部数据库均处于一致状态。
注:BDE4.5及以前的版本不实施两阶段提交,故永远不会产生Limbo事务。
两阶段提交过程如下:
在第一阶段,InterBase通过把从每个子事务(整体事务的一部分,只涉及一个数据库)中的更改写进相应的数据库为提交事务准备每个数据库。
在第二阶段,InterBase按照准备的次序将每个子事务标记为提交。
如果在第二阶段失败,一些子事务被提交到对应的数据库而另一些则没有。网络中断或磁盘崩溃均可能导致数据库无效,都有可能引起两阶段
提交失败。两阶段提交失败就会产生Limbo(遗弃)事务,InterBase服务器不知道这些事务是该提交还是改回滚,因此系统无法自动进行处理。
可以使用IBConsole恢复遗弃事务。选择数据库然后,使用主菜单DataBase|Maintence|Transaction Recovery恢复遗弃事务。在打开的对话
框中,一般情况下,使用推荐动作就足够了,因为系统会根据事务的状态自动给出提交或回退的建议。

使用命令行工具gfix可以进行如下维护工作:
1)数据库关闭
2)改变数据库模式:只读、读写
3)改变数据库的Dialect
4)设置数据库的缓存
5)提交遗弃事务
6)维护数据库并进行一定的修复
7)清扫数据库
8)显示、提交、恢复遗弃事务
要使用 gfix,必须是超级用户或者是数据库的宿主。gfix的语法是:gfix [option] db_name,其中,db_name是数据库名称,option是gfix
选项。option选项如下:
-ac[tivate]:当数据库无效时激活数据库影像。语法是:gfix -ac;不加数据库名字。
-at[tach] n:关闭数据库。和-shut一起使用,在数据库关闭期间阻止新的连接。如果超时n秒后仍有连接在工作,关闭被取消。
-b[?rs] n:设置数据库默认的缓存为n个数据页大小。
-ca[che] n:为将来功能保留。
-c[ommit]{ID|all}:事务恢复。提交由ID指定的Limbo事务或提交所有的Limbo事务。
-f[orce] n:数据库关闭。和-shut一起使用,在n秒后强制关闭数据库。
-f[ull]:数据修复。和-v一起使用,检查记录和数据页结构,释放未分配的记录段。
-h[ouskeeping] n:数据库清扫。设置自动清扫阀值为n个事务,当n为0时,则禁止自动清扫。缺省值是20000个事务,操作时不需要独占数据库。
-I[gore]:数据修复。当数据库进行校验或清扫时忽略校验和错误。
-l[ist]:事务恢复。显示每个Limbo事务的ID号,指明当-t选项使用进行自动两阶段提交时发生什么。

-m[end]:数据修复。将损坏的记录标记为无效。这些记录在诸如备份等操作中就被忽略。
-mo[de][read_write[[read_only]:设置数据库模式为只读或读写。缺省为读写模式。该操作要求独占数据库。
-n[o_update]:数据修复。和-v 选项一起使用,校验损坏或错误分配的结构,只报告但不修复。
-o[nline]:数据库关闭。取消一个安排好的-shut操作,或废除当前正在起作用的关闭操作。
-pa[ssword] text:提供远程访问时的密码。
-p[rompt]:事务恢复。和-l 选项一起使用,在事务恢复过程中提示有关动作。
-r[oolback]{ID|all}:事务恢复。回退由 ID 指定的 Limbo 事务或回退所有 Limbo 事务。
-s[weep]:数据库清扫。强制立刻执行数据库清扫。当自动数据库清扫禁止时特别有用,该操作不要求独占数据库。
-s[ql_dialect] n:改变数据库的 dialect。
-sh[ut]:关闭数据库,必须和-attch、-force 或-tran 一起使用。
-t[wo_phase]{ID|all}:事务恢复。对 ID 指定的 limbo 事务或所有 limbo 事务执行自动两阶段恢复。
-tr[an] n:数据库关闭。和-shut 一起使用在数据库关闭期间阻止任何新的事务。
-user name:远程登录,检查用户的有效性。
-v[alidate]:数据修复。查找并释放已经定位但未分配给任何数据结构的页,同时报告损坏的结构。
-w[rite][sync|async]:数据库写方式控制。设置是同步写(强制写)还是异步写(缓存写)。
-z:显示 gfix 和 InterBase 引擎版本号。

进行数据库备份和恢复的好处是:
1、对数据库数据进行保护,将数据存储到其他介质上,防止数据库因掉电、磁盘崩溃或其他潜在原因导致的数据丢失。
2、通过垃圾清除过期的记录提高数据库性能,并平衡索引。
3、释放删除记录所占用的空间,压缩数据,减小数据库的尺寸。
4、通过备份、恢复可以改变数据库的页面大小,或者将数据库分布到多个文件或磁盘上。
5、在线备份功能,备份的同时不影响用户对数据库的操作。当然,在备份之后写入的数据不会包含在备份文件中。
6、备份恢复功能满足了数据库的跨平台移植,通过备份和恢复,可以将数据库从一种平台无缝地移植到另一种平台,而不需要做额外的工作。
7、升级数据库文件ODS版本。出了重新安装新的InterBase数据库系统外,升级数据库文件ODS版本的唯一方法就是备份、恢复。升级数据库到新的 ODS :在安装新版本 的Interbase 之前,先将老版的数据库备份出来,然后安装新版的 Interbase ,安装完毕,将备份的数据库恢复出来。
注意,如果你使用多个备份文件,那么必须为除了最后一个备份文件之外的其它所有文件指定大小,而且其值不能小于2048字节。
IBConsole中的备份选项:
1、格式Format:可转移的/ 非可转移的
如果要将数据库转移到不同操作系统的机器上,如从 windows2000 到 linux ,要选择Transportable。
注:永远不要将数据库文件从一个机器拷贝到另一个机器,要先备份,再在其它机器上恢复。
2、只有元数据 Metadata Only:
若为Tr,则表示备份只包含元数据而不含数据。这在需要创建一个空数据库拷贝是很有用。
若为False,则表示备份既包含元数据结构又包含数据。
3、垃圾收集Garbage Collection
缺省情况下, IBConsole 在备份数据库的同时执行垃圾收集。垃圾收集可以将数据记录的过期版本占用的空间标记为可用。一般情况下,在备
份时要执行垃圾收集以优化数据库性能。
注:如果记录的过期版本有损坏的情况,最好不要执行垃圾收集,以免让 InterBase 在备份时访问这些记录。
4、遗弃事务Transactions in Limbo
Ignore:忽略遗弃事务,这样备份时就忽略掉所有遗弃事务产生的记录版本。只寻找最新提交的记录版本并备份它们。
Proccess:在备份的同时处理遗弃事务。
注:在备份一个含有遗弃事务的数据库前,最好先进行事务恢复。
5、校验和Checksums
Proccess:在执行备份前先进行数据库的和校验。如果发现校验和错误将终止备份。
Ignore:在进行数据库备份时忽略和校验。
6、数据表转换Convert to table
Tr:执行数据库备份时将外部数据表转换为内部表。
False:不进行这种转换。
7、备份信息的输出Verbose out
None:不输出备份时的信息。
To Screen:将备份时的信息输出到屏幕上。
To File:将备份时的信息输出到文件中。
IBConsole中的恢复选项:
1、覆盖Overwrite
Tr:覆盖一个已经存在的数据库文件。注意:需要超级用户或数据库宿主操作。
提示:不要替换一个用户正在操作的数据库,可以使用另外一个名字恢复数据库,然后再删除老的数据库。
Flase:恢复时则不覆盖数据库。
2、每个表之后提交Commit after each table
正常情况下, IBConsole 先恢复元数据,再恢复数据。设置该选项为Tr, IBConsole 则对表同时恢复数据和元数据,并一次提交一个表。
这个选项在恢复备份文件出现麻烦的时候很有用。例如,根据完整性约束出现的数据损坏或无效。因此,当备份文件出现问题时,每次向数
据库恢复一个数据表,这可原封不动的恢复一些数据。
3、创建影像文件Create shadow
如果想在恢复过程中创建数据库影像,选择Tr,否则选择False。
4、禁止索引deactivate indexes
正常情况下, InterBase 在恢复数据库时重建索引。如果在备份时数据库唯一索引上包含重复值,恢复将无效。重复值可能在暂时关闭索引
时引入数据库。这种情况下,为使恢复成功,设置该选项为真实的,禁止索引及索引重建。恢复完毕,通过改变索引Alter Index重建并激活
索引。唯一索引不能使用改变索引激活,必须先删除然后重建。
5、校验条件validity Conditions
如果数据库早已经输入了数据而后又重新定义了校验约束,这些数据可能不再满足校验约束。这点在恢复数据库之前可能发现不了,到时候就
会有一个无效数据的错误信息提示。当恢复一个包含无效数据的数据库时,设置该选项为不理睬,进行数据库恢复时将校验约束从元数据中删
除。恢复完毕,根据新的完整性约束更改数据使之有效。然后添加上被删除的约束。如果计划在恢复数据库后重新定义校验约束,本选项非常
有用。这样做后,一定要对数据作彻底测试。
6、使用所有空间Use all Space
Tr:在每个数据页上使用100%的填充率恢复数据。
False:使用80%的填充率(缺省)
7、恢复信息输出Verbose Out
分别为不输出、输出到屏幕、输出到文件。

gbak既可以用来备份数据库,又可以用来恢复数据库。当然,只有超级用户和数据库宿主才有权限使用该命令。
1、备份数据库
将数据库备份到单一文件中,语法:gbak [-b] [options] database target
将数据库备份到多个文件中,语法:gbak [-b] [options] database target1 size1[k|m|g] target2 size2[k|m|g] target3
当数据库为多文件数据库时,只指定第一个数据库文件名。其中参数说明:
database 为要备份的数据库名称,对于多文件数据库,只指定第一个数据库文件名。
Target 存储设备或备份文件的名称。
Gbak选项如下:
1)-b[ackup_database] 备份数据库到文件或设备
2)-co[nvert] 转换外部文件为内部表 3)-e[xpand] 创建一个未压缩的备份
4)-fa[ctor] n 对磁带设备使用块因子n
5)-g[arbage_collect] 备份期间禁止垃圾收集
6)-ig[nore] 备份期间忽略校验和
7)-l[imbo] 备份期间忽略遗弃事务
8)-m[etadata] 只备份元数据不备份数据
9)-nt 以非转移格式创建备份
10)-ol[d_description] 以旧的格式备份元数据
11) -pas[ssword] text 访问前验证密码text
12) –role name 由某个角色name连接
13) –se[rvice] servicename 使用InterBase的服务管理器(service manager)在原始数据库所在的宿主机器上创建备份文件。Servicename因本地服务器上不同的网络连接协议有不同的格式:
TCP/IP 宿主机器名:设备
SPX 宿主机器名@设备
Named Pipe \\宿主机器名\\设备
Local 设备
14)-t[ransportable] 创建转移格式的备份(缺省)
15)-u[ser] name 远程访问前校验用户名称name
16)-v[erbose] 显示命令的详细信息
17)-y[file|supress_putput] 将状态信息导入文件file中;suppress_out则禁止输出信息。
18)-z 显示InterBase引擎和gbak版本信息
当使用gbak命令行工具进行数据库备份时,应注意以下几点:
1)只有超级用户和数据库宿主才能备份数据库
2)除非指定service选项,否则gbak总是将备份文件写到它所在的目录中,而不是数据库所在的服务器上。如果你为备份文件指定了一个位置,那么此位置也是相对于gbak当前目录的。这就是说,备份文件总是写到本地机器上的。当然使用InterBase服务管理器可以改变这种情形。
3)当备份一个多文件数据库时,在gbak命令中只能指定第一个数据库文件的名称。
4)备份文件的缺省单位为字节,当然也可以选择使用千字节、兆字节、吉字节等。但是恢复的数据库文件只能使用数据页作为单位。
5)为安全起见,最好把备份文件设置成只读属性以防止意外改写,此外,最好将备份文件放在具有一定权限的目录中以禁止任意用户的随意访问。
6)如果要想在数据库所在的服务器上进行备份,使用-service选项。
7)在跨多个平台的环境下操作,最好使用-transportable选项,以方便数据库的移植。
2、恢复一个数据库
语法:gbak {-c|-r} [options] source dbfile
恢复到多个数据库文件:gbak {-c|-r}[options] source dbfile1 size1 dbfile2 [size2 dbfile3]
从多个备份文件中恢复数据库:
gbak {-c|-r}[options] source1 source2 [source3…] dbfile
从多个备份文件中恢复到多个数据库文件:
gbak {-c|-r}[options] source1 source2 [source3] dbfile1 size1 dbfile2 [size2 dbfile3]
其中:source为数据库备份文件,dbfile为数据库文件。
恢复选项如下:
1)-c[reate_database] 将数据库恢复到一个新文件
2)-bu[ffers] 为恢复数据库的设置缓存大小
3)-i[nactive] 禁止索引活动
4)-k[ill] 不创建先前定义的任何影像。
5)-m[ode [rea_write|read_only] 指定恢复的数据库的读写模式
6)-n[o_validity] 从恢复的元数据中删除校验约束,允许恢复不满足校验约束的数据。
7)-o[ne_at_a_time] 一次恢复一个数据表。当数据库中包含损坏的数据时,进行部分恢复。
8)-p[age_size] n 重新设置页面大小为n字节(1024,2048,4096,8192),缺省为1024。
9)-pa[ssword] text 访问数据库前校验密码。
10)-r[eplace_database] 恢复数据库到一个新文件或替换已经存在的文件。
11)-se[rvice] servicename 使用InterBase的服务管理器(service manager),在备份文件所在的宿主机上创建恢复数据库。Servicename因本地服务器上不同的网络连接协议有不同的格式:
TCP/IP 宿主机器名:设备
SPX 宿主机器名@设备
Named Pipe \\宿主机器名\\设备
Local 设备
12)-user name 访问数据库前校验用户名。
13)-use_[all_space] 在每个数据页上使用100%的填充率恢复数据库,而不是使用缺省的80%填充率。
14)-v[erbose ] 显示gbak恢复信息。
15)-y[file|suppress_output] 和选项-v一起起作用,将状态信息输出到文件中。如果不和-v一起使用而且省略file,将禁止输出信息。
16)-z 显示gbak和InterBase引擎版本信息。
当恢复一个数据库时,一定要牢记:
1)任何用户都能恢复一个数据库,然而,只有数据库宿主和超级用户擦能在一个已经存在的数据库上恢复数据库。
2)不要在一个正在使用的数据库上作备份恢复,有可能损坏数据库。
3)当从一个多文件的备份中作恢复时,命名所有的备份文件,文件的顺序不重要。
4)不要为恢复的数据库的最后一个文件或只有一个文件的数据库文件指定大小,InterBase会自动扩展它们的大小。
5)为恢复的数据库指定大小时以数据页为单位。缺省情况下一个数据库文件为200个数据页,每页为1k,因此缺省的数据库大小为200k。可以使用-p[age_size]选项改变这个值。

InterBase的安全完全依赖于一个所谓的安全数据库,该数据库名称为admin.ib,在InterBase7.0以前的版本中叫isc4.gdb,它记录了允许连
接到InterBase的合法用户,其中每条记录包含了用户登录名和加密的登录密码,它们适用于该机上所有InterBase数据库。用户名最多31个字
符,且大小写不敏感,密码8个字符,大小写敏感。要严格管理控制InterBase安装目录的权限,确保InterBase的安全。安全数据库中的用户
是全局性的,对所有的数据库都有效。但对某个特定的数据库来说,并不是所有的用户都需要,在Interbase中用角色来管理用户对某个数据库
的特定权限。角色是相对于特定数据库而言的,角色作为数据库对象存放在数据库中,不同的数据库可能拥有不同的角色。Interbase数据库有
两个默认的角色:SYSDBA和P LIC,要实现一个角色需要4个步骤:
1、创建角色
创建角色的语法是:Create Role 角色名;
例如:Create Role Sales;/*创建一个叫Sales的角色*/
2、对角色进行授权
例如:Grant Update On Table1 To Sales;/*将表Table1的更改权限赋给角色Sales*/
详细的授权我们在下一节介绍。
3、用户通过角色连接到数据库
例如:Connect ‘Mydb’ User ‘User1’ Password ‘pwd1’ Role Sales;
这样用户User1就可以更改表Table1了。需要特别注意的是,一个用户每次连接只能属于一个角色,而且在连接期间不能更换角色。要改变角
色,用户必须退出数据库然后以新的角色重新连接到数据库。

InterBase中支持的访问权限。
All权限:包括Select、Update、delete、Insert、Reference引用,但不包括Execute权限。
Select权限:读取数据。
Update权限:更改数据。
Delete权限:删除数据。
Insert权限:插入数据。
Execute权限:执行或调用存储过程。
Reference引用权限:外键引用主键。

可以被授权的对象包括:表、视图、存储过程、触发器。
InterBase使用Grant进行授权,使用Revoke将权限回收。

1、授权语句Grant的语法是:
GRANT {
      < privileges> ON [TABLE] {tablename | viewname} TO {<object> | <userlist> | GROUP UNIX_group} /*授权对表或视图的操作*/
      | EXECUTE ON PROCEDURE procname TO {<object> | <userlist>}          /*授权对存储过程的执行*/
      | < role_granted> TO {P LIC | < role_grantee_list>}           /*将拥有某些权限的角色授予某些用户*/
      };
其中:
权限列表就是上述的权限:
< privileges> = {ALL [PRIVILEGES] | < privilege_list>}
<privilege_list> = SELECT | DELETE | INSERT | UPDATE [( col [, col …])] | REFERENCES [( col [, col …])] [, < privilege_list> …]
注意Update和Reference权限可以分配到列。
被授权的对象有:
<object> = PROCEDURE procname | TRIGGER trigname | VIEW viewname | P LIC [, <object> …]
用户列表指出了被授权的用户或角色:
<userlist> = [USER] username | rolename | Unix_user [, <userlist> …]
[WITH GRANT OPTION]
已经被授权的角色:
< role_granted> = rolename [, rolename …]
<role_grantee_list> = [USER] username [, [USER] username …]
[WITH ADMIN OPTION]

2、权限回收语句Revoke的语法是:
REVOKE [GRANT OPTION FOR] {
      < privileges> ON [TABLE] { tablename | viewname} FROM { <object> | <userlist> | < rolelist> | GROUP UNIX_group}
      | EXECUTE ON PROCEDURE procname FROM { <object> | <userlist>}
      | < role_granted> FROM {P LIC | < role_grantee_list>}
      };
< privileges> = {ALL [PRIVILEGES] | < privilege_list>}
<privilege_list> = {SELECT| DELETE| INSERT| UPDATE [( col [, col …])]| REFERENCES [( col [, col …])][, < privilege_list> …]}}
<object> ={PROCEDURE procname| TRIGGER trigname| VIEW viewname| P LIC[, <object>]}
<userlist> = [USER] username [, [USER] username …]
< rolelist> = rolename [, rolename]
< role_granted> = rolename [, rolename …]
<role_grantee_list> = [USER] username [, [USER] username …]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值