fastdb的资料

 
一、介绍
              FastDb是高效的内存数据库系统,具备实时能力及便利的C++接口。
FastDB不支持client-server架构因而所有使用FastDB的应用程序必须运行在同一主机上。
FastDB针对应用程序通过控制读访问模式作了优化。通过降低数据传输的开销和非常有效的锁机制提供了高速的查询。对每一个使用数据库的应用数据库文件被影射到虚拟内存空间中。因此查询在应用的上下文中执行而不需要切换上下文以及数据传输。
fastdb中并发访问数据库的同步机制通过原子指令实现,几乎不增加查询的开销。fastdb假定整个数据库存在于RAM中,并且依据这个假定优化了查询算法和接口。
此外,fastdb没有数据库缓冲管理开销,不需要在数据库文件和缓冲池之间传输数据。这就是fastdb运行速度明显快于把数据放在缓冲池中的传统数据库的原因。 fastdb支持事务、在线备份以及系统崩溃后的自动恢复。事务提交协议依据一个影子根页面算法来自动更新数据库。恢复可以执行得非常快,为临界应用提供了高可用性。此外,取消事务日志改进了整个系统的性能,并且使得可以更有效的利用系统资源。 fastdb是一个面向应用的数据库,数据库表通过应用程序的类信息来构造。fastdb支持自动的模式评估,使你可以只需要在一个地方更改-你的应用程序的类。fastdb提供一个灵活方便的接口来从数据库中获取数据。使用一个类SQL的查询语言进行指定的查询。通过一些后关系特性如非原子字段,嵌套数组,用户定义类型和方法,对象间直接引用简化了数据库应用程序的设计并使之更有效率。尽管fastdb的优化是立足于假定整个数据库配置在计算机的物理内存中,但是也有可能出现使用的数据库的大小超过了系统物理内存的大小的情况,在这种情况下标准的操作系统交换机制就会工作。但是整个fastdb的搜索算法和结构是建立在假定所有的数据都存在于内存中的,因此数据换出的效率不会很高。 查询语言 fastdb支持一个类sql句法的查询语言。fastdb使用更流行于面向对象程序设计的表达式而不是关系数据库的表达式。表中的行被认为是对象实例,表是这些对象的一个类。与sql不同,fastdb面向的是对对象的操作而不是对sql元组。所以每一次查询的结果就是来自一个类的对象的集合。fastdb查询语言与标准sql的主要差别在于: 1.不支持多个表之间的连接(join)操作,不支持嵌套子查询。查询总是返回来自一个表的对象的集合。 2.原子表列使用标准的c数据类型 3.没有NULL值,只有null引用。我完全同意C.J.Date对3值逻辑的批评以及他使用缺省值来代替NULL的意图 4.结构和数组可以作为记录元素。一个特别的exists算子(quantor)用来定位数组中的元素 5.可以为表记录(对象)也可以为记录元素定义无参用户自定义方法, 6.应用程序可以定义只有一个串或者数值类型参数的用户自定义函数 7.支持对象间的引用,包括自动支持逆引用 8.通过使用引用,start from follow by执行递归的记录遍历。 9.因为查询语言深度继承在了c++类中,语言标识符和关键字是大小写敏感的 10. 不进行整形和浮点型到串的隐含转换,如果需要这样的转换,必须显式进行下面类BNF表达式的规则指定了Fastdb查询语言搜索断言的语法: Grammar conventions Example Meaning expression non-terminals not terminals | disjoint alternatives (not) optional part {1..9} repeat zero or more times select-condition ::= ( expression ) ( traverse ) ( order )expression ::= disjunctiondisjunction ::= conjunction | conjunction or disjunctionconjunction ::= comparison | comparison and conjunctioncomparison ::= operand = operand | operand != operand | operand <> operand | operand < operand | operand <= operand | operand > operand | operand >= operand | operand (not) like operand | operand (not) like operand escape string | operand (not) in operand | operand (not) in expressions-list | operand (not) between operand and operand | operand is (not) nulloperand ::= additionadditions ::= multiplication | addition + multiplication | addition || multiplication | addition - multiplicationmultiplication ::= power | multiplication * power | multiplication / powerpower ::= term | term ^ powerterm ::= identifier | number | string | true | false | null | current | first | last | ( expression ) | not comparison | - term | term [ expression ] | identifier . term | function term | exists identifier : termfunction ::= abs | length | lower | upper | integer | real | string | user-functionstring ::= ' { { any-character-except-quote } ('') } 'expressions-list ::= ( expression { , expression } )order ::= order by sort-listsort-list ::= field-order { , field-order }field-order ::= [length] field (asc | desc)field ::= identifier { . identifier }traverse ::= start from field ( follow by fields-list )fields-list ::= field { , field }user-function ::= identifier标识符大小写敏感,必须以一个a-z,A-Z ,_ 或者$字符开头,只包含a-z, A-Z, 0-9,_或者$字符,不能使用SQL保留字。 保留字列表 abs and asc between by current desc escape exists false first follow from in integer is length like last lower not null or real start string true upper 可以使用ANSI标准注释,所有位于双连字符后直到行末的字符都将被忽略掉。 fastdb扩展了ansi标准sql操作符,支持位运算。and/of操作符不仅可以运用到布尔操作数也可以操作整形操作书。and/or运用到整形操作数返回的结果是一个整形值,这个值是对操作数进行按位and或者按位or得到的结果。对于小的集合位运算是高效的。fastdb也支持对整形和浮点型的升幂运算(x^y) Structures fastdb接受结构体作为记录的元组。结构的字段可以通过标准的点表达式访问:company.address.city 结构体的字段可以索引,从而可以按照指定的序列使用。结构体可以包含其他的结构体作为其元组,嵌套深度没有限制。程序员可以为结构体定义方法,这些方法可以用在查询中,与对普通结构元组的句法是一样的。这些方法除了一个指向其隶属的对象的指针外(C++中的this指针)不能有参数,并且返回原子类型(bool型,数值、字符串或者引用类型)。这些方法也不应该改变对象实例(immutable method).如果方法返回字符串,该字串必须用new字符操作符分配,因为该字串值拷贝之后就会被删掉。因此用户自定义方法可以用来创建虚元组-不是保存在数据库中而是使用其他元组计算出来的元组。例如:fastdb的dbDateTime类型只包含整形时间戳元组和象dbDateTime::year(), dbDateTime::month()...这样的方法。因此可以在应用中指定象"delivery.year = 1999"这样的查询,其中delivery记录字段拥有dbDateTime类型。方法在应用的上下文中执行,在其中定义,对其他应用和交互SQL是无效的 Arrays fastdb接受动态数组作为记录元组,不支持多维数组,但可以定义数组的数组,可以按照结果集中数组字段的长度对记录排序。fastdb提供了一个特别的构造集来处理数组: 1.可以用length()函数来取得数组中元素的数目。 2.数组元素可以用[]操作符来获取。如果索引表达式超出了数组范围,将产生异常 3.in操作符可以用来检查一个数组是否包含有一个由左操作书指定的值。该操作只能用于原子类型的数组:boolean , 数值,引用和字符串。 4.数组可以用update方法更新,该方法复制数组然后返回一个非常量的引用。 5.使用exists运算符迭代数组元素。exists关键字后指定的变量可以作为在exists算子后面的表达式中的数组的索引。该索引变量将迭代所有可能的数组索引值,直到表达式的值为true或者索引越界,下面的情况: exists i: (contract[i].company.location = 'US')将选择由位于‘US'的公司载运的合同的所有细节,而下面的查询:not exists i: (contract[i].company.location = 'US')将选择由'us'之外的公司载运的合同的所有细节可以由嵌套的exists子句。使用嵌套exist算子等同于使用相应的索引变量的嵌套循环。例如查询 exists column: (exists row: (matrix[column][row] = 0))将选择matrix字段的元素为0的所有记录,该字段拥有整形数组的数组数据类型。这个构造等同于下面的两层嵌套循环:bool result = false; for (int column = 0; column < matrix.length(); column++) { for (int row = 0; row < matrix[column].length(); row++) { if (matrix[column][row] == 0) { result = true; break; } } } Strings fastdb中的所有字符串都是变长的因此程序员无需费心去指定字符字段的最大长度,所有对数组适用的操作也适用于字符串。此外字符串也有属于自己的操作集。首先,字符串可用标准关系运算符相互比较。目前,fastdb只支持ascii字符集(对应于c的char类型)以及对字符串逐字节的比较而忽略本地设置。 like运算符可以通过一个包含通配符'%'和'_'的模式来匹配字符串, 。'_'字符匹配任意的单个字符,'%'匹配0个或多个字符。like运算符的一个扩展形式是与escape关键字一起用来处理模式中的'%'和'_'字符,如果他们出现在一个特定的逃逸字符之后(指escape关键字)就被当作普通字符处理而不是通配符。可以用in操作符在字符串中查找子串。表达式 ('blue' in color)对于所有包含color字段包含'blue'的记录都为真。如果被查找的字符串的长度大于某个门槛值(当前为512),则使用boyer-moore子串查找算法而不是直接查找方式。字符串可以用+或者||运算符进行连接,后者是为了与ansi sql标准的兼容性而加入的。由于fastdb不支持在表达式中隐含的字符串转换,因此+运算符的语义可以为字符串重新定义References 引用通过点表达式来解析,如:company.address.city = 'Chicago',可以用is null和is not null来检查引用是否为空。也可以与null关键字进行是否相等的比较。当解析一个null应用时,fastdb会抛出异常。 fastdb不支持连接操作,连接操作可以用引用来实现,如下面例子: struct Detail { char const* name; double weight; TYPE_DESCRIPTOR((KEY(name, INDEXED), FIELD(weight))); }; struct Supplier { char const* company; char const* address; TYPE_DESCRIPTOR((KEY(company, INDEXED), FIELD(address))); }; struct Shipment { dbReference detail; dbReference supplier; int4 price; int4 quantity; dbDateTime delivery; TYPE_DESCRIPTOR((KEY(detail, HASHED), KEY(supplier, HASHED), FIELD(price), FIELD(quantity), FIELD(delivery))); }; 我们需要得到来自于某个suppliers的delivery的details信息,在关系数据库中有如下查询: select from Supplier,Shipment,Detail where Supplier.SID = Shipment.SID and Shipment.DID = Detail.DID and Supplier.company like ? and Supplier.address like ? and Detail.name like ? 在fastdb中就写成这样: dbQuery q = "detail.name like",name,"and supplier.company like",company, "and supplier.address like",address,"order by price"; Functions Predefined functions Name Argument type Return type Description abs integer integer absolute value of the argument abs real real absolute value of the argument integer real integer conversion of real to integer length array integer number of elements in array lower string string lowercase string real integer real conversion of integer to real string integer string conversion of integer to string string real string conversion of real to string upper string string uppercase string fastdb允许用户自行定义函数和运算符,函数至少需要一个参数,但不能超过3个。参数类型必须为string、integer、boolean、reference或者用户定义类型(raw binary) 用户自定义函数必须使用USER_FUNC(f)宏注册。 2. C++接口 fastdb中可以用c++写出如下的查询: dbQuery q; dbCursor contracts; dbCursor suppliers; int price, quantity; q = "(price >=",price,"or quantity >=",quantity, ") and delivery.year=1999"; // input price and quantity values if (contracts.select(q) != 0) { do { printf("%s\n", suppliers.at(contracts->supplier)->company); } while (contracts.next()); Table fastdb的数据存储在table中,这对应于C++类,表记录则对应于类实例。下面是可以做为fastdb记录原子组件的C++类型: Type Description bool boolean type (true,false) int1 one byte signed integer (-128..127) int2 two bytes signed integer (-32768..32767) int4 four bytes signed integer (-2147483648..2147483647) int8 eight bytes signed integer (-2**63..2**63-1) real4 four bytes ANSI floating point type real8 eight bytes ANSI double precision floating point type char const* zero terminated string dbReference reference to class T dbArray dynamic array of elements of type T 除此之外,fastdb记录也包括包含这些componets的嵌套的结构。fastdb不支持unsigned类型。下面是定义一个table的例子,可以放在头文件中:class dbDateTime { int4 stamp; public: int year() { return localtime((time_t*)&stamp)->tm_year + 1900; } ... CLASS_DESCRIPTOR(dbDateTime, (KEY(stamp,INDEXED|HASHED), METHOD(year), METHOD(month), METHOD(day), METHOD(dayOfYear), METHOD(dayOfWeek), METHOD(hour), METHOD(minute), METHOD(second)));}; class Detail { public: char const* name; char const* material; char const* color; real4 weight; dbArray< dbReference > contracts; TYPE_DESCRIPTOR((KEY(name, INDEXED|HASHED), KEY(material, HASHED), KEY(color, HASHED), KEY(weight, INDEXED), RELATION(contracts, detail)));}; class Contract { public: dbDateTime delivery; int4 quantity; int8 price; dbReference detail; dbReference supplier; TYPE_DESCRIPTOR((KEY(delivery, HASHED|INDEXED), KEY(quantity, INDEXED), KEY(price, INDEXED), RELATION(detail, contracts), RELATION(supplier, contracts)));}; 定义了表之后,就需要用REGISTER(name)宏来注册,也就是把上面定义的类与表联系起来:REGISTER(Detail);REGISTER(Supplier);REGISTER(Contract); 这个宏应该放在实现而不是头文件中。当数据库新注册的表与库中原有的表同名时,fastdb会比较两个表,如果定义不同,fastdb会把原来的表更新成新的表,可以添加新字段,但是删除字段只有在原来的表为空的时候才可以进行。有一个特殊的内部数据库表Metatable,保存了这个数据库中其他所有表的信息。支持自动增加字段。 Query The class query is used to serve two purposes: to construct a query and bind query parameters to cache compiled queries 例子: dbQuery q; int price, quantity; q = "price >=",price,"or quantity >=",quantity;给上面的参数price,quantity赋不同的值查询可以得到不同的结果,不能用数值常量作查询参数,但是可以用字符串常量作查询参数。 有两个方法来给字符串类型的参数赋值: dbQuery q; char* type; char name[256]; q = "name=",name,"and type=",&type; scanf("%s", name); type = "A"; cursor.select(q); ... scanf("%s", name); type = "B"; cursor.select(q); ... CursorCursors用于访问查询语句返回的记录。fastdb提供有类型的cursor,即与具体表关联的cursor.fastdb有两种cursor:只读cursor和用于更新的cursor.fastdb中cursor用c++模板类dbCursor表示,T为一个与表关联的C++类的名字。cursor的类型必须在构造时指定,缺省时只读的。要创建一个用于更新的cursor,必须向constructor传递参数dbCursorForUpdate,如:dbCursor contract(dbCursorForUpdate); 查询通过执行cursor的select(dbQuery& q)或者select()方法,后者用来迭代表中的所有记录。两个方法都返回查询选择的记录数并且置cursor的当前位置为第一个记录(如果存在的话)。一个cursor可以向前向后滚动,next(),prev(),first(),last()方法用来改变cursor的当前位置,如果由于没有更多记录而使得这些操作进行下去,则这些操作返回NULL,并且当前的cursor位置不变。 C++ API定义了null引用类型,可以将null与reference比较或者将其赋给reference: void update(dbReference c) { if (c != null) { dbCursor contract(dbCursorForUpdate); contract.at(c); contract->supplier = null; } } query参数通常与C++变量绑定,解决多线程同一query不同参数执行的问题 ,Fastdb采用了延迟参数绑定的方法: dbQuery q; struct QueryParams { int salary; int age; int rank; }; void open() { QueryParams* params = (QueryParams*)NULL; q = "salary > ", params->salary, "and age < ", params->age, "and rank =", params->rank; } void find(int salary, int age, int rank) { QueryParams params; params.salary = salary; params.age = age; params.rank = rank; dbCursor cusor; if (cursor.select(q, & params) > 0) { do { cout << cursor->name << NL; } while (cursor.next()); } } So in this example function open binds query parameters just to offsets of fields in structure. Later in find functions, actual pointer to the structure with parameters is passed to the select structure. Function find can be concurrently executed by several threads and only one compiled version of the query is used by all these threads. This mechanism is available since version 2.25. Database dbDatabase类控制应用与数据库的交互。同步数据库的并发访问,事务管理,内存分配,错误处理,。。。构造dbDatabase对象时可以指定数据库参数: dbDatabase(dbAccessType type = dbAllAccess, size_t dbInitSize = dbDefaultInitDatabaseSize, size_t dbExtensionQuantum = dbDefaultExtensionQuantum, size_t dbInitIndexSize = dbDefaultInitIndexSize, int nThreads = 1); 当database主要是以readonly模式访问并且更新不能长时间锁定读的时候应当同时使用dbConcurrentUpdate和dbConcurrentRead模式。在这种模式下,更新数据库可以与读访问并发进行(reader将看不到改变的数据,直到事务提交),只有在事务提交时才设置排它锁并且当更新了当前对象的索引后会马上释放。 Attension! Do not mix dbConcurrentUpdate and dbConcurrentRead mode with other modes and do not use them together in one process (so it is not possible to start two threads in one of which open database in dbConcurrentUpdate mode and in other - in dbConcurrentRead). Do not use dbDatabase::precommit method in dbConcurrentUpdate mode. 使用open(char const* databaseName, char const* fileName = NULL, unsigned waitLockTimeout = INFINITE)方法打开数据库。如果fileName为空,则自动在databaseName加上'.fdb'形成数据库文件名,waitLockTimeout用来设置一个进程被锁住的最大时间,当过期后,被锁住的活动进程就自动恢复执行。使用dbDatabase::backup(char const* file)方法备份数据库。恢复只需要改文件名。 3. CLI接口 fastdb提供了多线程的server处理客户的cli会话。在SubSql中用命令start server 'HOST:PORT' 启动server.如果会话异常中止,该client的所有改变将会回滚。server通过stop server 'HOST:PORT'停止。 退出subsql也会停止server. 4. CLI接口本地实现 cli函数的本地实现包含在fastdb库中,如果要使用远程cli,用cli.lib,如果本地访问数据库,用fastdb.lib连接, 5. SubSql select (*) from table-name select-condition ; | insert into table-name values values-list ; | create index on on table-name.field-name ; | create table table-name (field-descriptor {, field-descriptor}) ; | alter table table-name (field-descriptor {, field-descriptor}) ; | update table-name set field-name = expression {, field-name = expression} where condition ; | drop index table-name.field-name ; | drop table table-name | open database-name ( database-file-name ) ; | delete from table-name | backup file-name | start server server-URL number-of-threads | stop server server-URL | start http server server-URL | stop http server server-URL | export xml-file-name | import xml-file-name | commit | rollback | autocommit (on | off) | exit | show | help · 二、Quick start 开发fastdb应用时,首先要确定需要存储在数据库中的数据和类。通过REGISTER宏注册表标识符。如果想要重定义缺省的fastdb出错处理,就要从dbDatabase继承定义自己的数据库类。应当创建一个该类的实例并且使之能够让所有的应用模块访问。在操作数据库前,首先要打开。检查dbDatabase::open()的返回码确定数据库是否成功返回。在数据库打开过过程中出错并不会中止应用不过回报告。确认数据库正常打开后,就可以开始工作。如果是多线程的应用并且多个线程会使用同一个数据库,就用dbDatabase::attach方法把每一个线程与数据库连接起来。在线程终止前,应该通过dbDatabase::detach()方法将其与数据库剥离。为了访问数据库的数据,需要创建一些dbQuery和dbCursor对象,如果多个线程同时工作于一个数据库,每一个线程都要有自己query和cursor对象。通常一个表有一个cursor就够了(或者两个,如果应用需要更新数据库的话)。但在嵌套查询时也需要使用多个cursor 。每一种类型的查询都需要创建一个query对象,query对象也用来缓存编译好的查询。数据库有4个主要操作:insert, select, update, remove. 第一个操作不需要cursor,而使用全局重载的模版函数insert。选择,更新和删除记录需要使用cursor。要改变表就必须使用用于更新的cursor. 在fastdb中cursor是类型化的,并且包含一个table类的对象实例。重载的cursor运算符‘->'能够用来访问当前记录的组件,也能够用来更新这些组件。update方法把当前cursor对象的数据复制到当前的表记录中。remove方法将移除当前cursor记录,removeAllSelected将移除所有中选的记录,removeAll将移除表中所有的记录。每一个事务由dbDatabase::commit()提交或者由dbDatabase::rollback()中止。在第一个select 、insert或者remove操作执行时就自动开始一个事务。 在退出应用前要记住关闭数据库,同时也要记得dbDatabase::close()方法会自动提交最后一个事务。因此如果这不是你所想的操作,推出前显式调用dbDatabase::rollback 一个fastdb应用的模版: //// Header file//#include "fastdb.h" extern dbDatabase db; // create database object class MyTable { char const* someField; ... public: TYPE_DESCRIPTOR((FIELD(someField)));}; //// Implementation//REGISTER(MyTable); int main() { if (db.open("mydatabase")) { dbCursor cursor; dbQuery q; char value[bufSize]; q = "someField=",value; gets(value); if (cursor.select(q) > 0) { do { printf("%s\n", cursor->someField); } while (cursor.next()); } db.close(); return EXIT_SUCCESS; } else { return EXIT_FAILURE; }} . 要编译fastdb应用,需要包含头文件fastdb.h,该头文件包含了其他的fastdb头文件,所以要保证fastdb目录在编译器的include路径中。要连接fastdb应用,需要fastdb库(windows fastdb.lib/unix libfastdb.a). 创建fastdb库,只需要在fastdb目录下make。fastdb发布没有自动配置工具。大多数系统依赖代码都使用条件编译,fastdb发布有两个makefile,一个是用于ms windows vc++(makefile.mvc),另一个是用于unix gcc(makefile), 如果需要使用posix线程或者其他一些编译器可以编辑该makefile.make.bat只是执行一条nmake –f makefile.mvc命令。Unix makefile的install标志将把fastdb头文件,fastdb库文件以及subsql工具复制到makefile INCSPATH, LIBSPATH和BINSPATH变量指定的相应目录中,这些变量缺省值为: INCSPATH=/usr/include LIBSPATH=/usr/lib BINSPATH=/usr/bin The database trace can be switched on (by (re-)compiling the FastDB library with the -DDEBUG=DEBUG_TRACE option) to perform analysis of database functionality and efficiency of using indices.应用需要扩展的情况下,fastdb可以自动的扩展模式如增加字段改变字段的类型。程序员也可以增加新的索引或者移除很少使用的索引,通过(重)编译(使用-DDEBUG=DEBUG_TRACE选项)fastdb库来分析数据库使用索引的性能和效率。 .subsql工具可以用于浏览和检查数据库,进行在线备份,导入导出数据库的数据。fastdb在系统或者应用崩溃后可以自动恢复。唯一需要手工做的事情是当操作数据库的应用中某一个崩溃后停止所有的数据库应用以解除数据库被锁住。

你可能感兴趣的:(数据库,String,null,Integer,makefile,Descriptor)