用于PHP的文档存储,该存储允许倍数并发。它是MongoDB或CouchDB的简约替代品,而没有安装新服务的开销。
它还可以充当一个小的足迹数据库。
平均而言,SMB每月产生100张发票。因此,假设SMB每十年生成12000个发票。
测试与客户一起生成12000个发票,详细信息(每个详细信息约1-5行),以及i7/ssd/16GB/Windows 64bits上的日期。

进行100次并发测试的测试(写和阅读)10次。
| n° | 阅读 | (多发性硬化症) | 阅读 | 错误 |
|---|---|---|---|---|
| 1 | 100 | 7471 | 100 | 0 |
| 2 | 100 | 7751 | 100 | 0 |
| 3 | 100 | 7490 | 100 | 0 |
| 4 | 100 | 7480 | 100 | 0 |
| 5 | 100 | 8199 | 100 | 0 |
| 6 | 100 | 7451 | 100 | 0 |
| 7 | 100 | 7476 | 100 | 0 |
| 8 | 100 | 7244 | 100 | 0 |
| 9 | 100 | 7573 | 100 | 0 |
| 10 | 100 | 7818 | 100 | 0 |
include " lib/DocumentStoreOne.php " ;
use eftec DocumentStoreOne DocumentStoreOne ;
try {
$ flatcon = new DocumentStoreOne ( " base " , ' tmp ' );
// or you could use:
// $flatcon = new DocumentStoreOne(__DIR__ . "/base", 'tmp');
} catch ( Exception $ e ) {
die ( " Unable to create document store. Please, check the folder " );
}
$ flatcon -> insertOrUpdate ( " somekey1 " , json_encode ( array ( " a1 " => ' hello ' , " a2 " => ' world ' ))); // or you could use serialize/igbinary_serialize
$ doc = $ flatcon -> get ( " somekey1 " );
$ listKeys = $ flatcon -> select ();
$ flatcon -> delete ( " somekey1 " ); include " lib/DocumentStoreOne.php " ;
use eftec DocumentStoreOne DocumentStoreOne ;
$ doc = new DocumentStoreOne ( " base " , " task " , ' folder ' );
//also: $doc=new DocumentStoreOne(__DIR__."/base","task",'folder');
$ doc -> serializeStrategy = ' php ' ; // it sets the strategy of serialization to php
$ doc -> autoSerialize ( true ); // autoserialize
$ flatcon -> insertOrUpdate ( " somekey1 " , array ( " a1 " => ' hello ' , " a2 " => ' world ' )); 它创建文档storeone实例。
| 战略 | 类型 | 服务器 | 基准 |
|---|---|---|---|
| DSO_AUTO | 它设定了最佳可用策略(默认) | 取决于 | - |
| DSO_FOLDER | 它使用文件夹来锁定/解锁文档 | - | 0.3247 |
| DSO_APCU | 它使用apcu锁定/解锁文档 | - | 0.1480 |
| dso_redis | 它使用redis锁定/解锁文档 | Localhost:6379 | 2.5403(最坏) |
| dso_none | 它无需锁定/解锁文档。这是最快的方法,但对于用户而言,它是不安全的 | 0 |
| 战略 | 类型 |
|---|---|
| php | 它使用serialize()函数序列化 |
| php_array | 它使用include()/var_export()函数序列化。结果可以在OPCACHE上缓存,因为结果是PHP代码文件。 |
| json_object | 它是使用JSON(作为对象)序列化的 |
| JSON_ARRAY | 它使用JSON(作为数组)序列化 |
| CSV | 它使用CSV文件序列化。 |
| igbinary | 它使用igbinary文件序列化。 |
| 无(默认值) | 它不是序列化的。信息必须手动序列化/除外序列化 |
示例:
$ flatcon = new DocumentStoreOne ( __DIR__ . " /base " ); // new instance, using the folder /base, without serialization and with the default data
$ flatcon = new DocumentStoreOne ( __DIR__ . " /base " , '' , ' auto ' , '' , ' php_array ' ); // new instance and serializing using php_array基准添加100个插入物需要多少时间(以秒为单位)。
use eftec DocumentStoreOne DocumentStoreOne ;
include " lib/DocumentStoreOne.php " ;
try {
$ flatcon = new DocumentStoreOne ( __DIR__ . " /base " , ' tmp ' );
} catch ( Exception $ e ) {
die ( " Unable to create document store. " . $ e -> getMessage ());
} use eftec DocumentStoreOne DocumentStoreOne ;
include " lib/DocumentStoreOne.php " ;
try {
$ flatcon = new DocumentStoreOne ( " /base " , ' tmp ' ,DocumentStoreOne:: DSO_APCU );
} catch ( Exception $ e ) {
die ( " Unable to create document store. " . $ e -> getMessage ());
}如果收集有效(子文件夹),则返回为true。
$ ok = $ flatcon -> isCollection ( ' tmp ' );它设置了当前集合
$ flatcon -> collection ( ' newcollection ' ); // it sets a collection.该命令可以嵌套。
$ flatcon -> collection ( ' newcollection ' )-> select (); // it sets and return a query请注意,它无法验证该集合是否正确或存在。您必须使用ISCollection()来验证是否正确。
如果我们想自动序列化信息,它将设置它,并将其设置如何序列化。您也可以使用构造函数设置。
| 战略 | 类型 |
|---|---|
| php | 它使用serialize()函数序列化。 |
| php_array | 它使用include()/var_export()函数序列化。结果可以在OPCACHE上缓存,因为结果是PHP文件 |
| json_object | 它是使用JSON(作为对象)序列化的 |
| JSON_ARRAY | 它使用JSON(作为数组)序列化 |
| CSV | 它使用CSV文件序列化。 |
| igbinary | 它使用igbinary文件序列化。 |
| 无(默认值) | 它不是序列化的。信息必须手动序列化/除外序列化 |
它创建一个集合(基本文件夹内的新文件夹)。如果操作失败,它将返回false;否则它将返回真实
$ flatcon -> createCollection ( ' newcollection ' );
$ flatcon -> createCollection ( ' /folder1/folder2 ' ); 将新文档(字符串)插入指定的$ ID中。如果文档存在,则已更新。
$尝试表示尝试的数量。默认值为-1(默认尝试数)。
// if we are not using auto serialization
$ doc = json_encode ([ " a1 " => ' hello ' , " a2 " => ' world ' ]);
$ flatcon -> insertOrUpdate ( " 1 " , $ doc ); // it will create a document called 1.dson in the base folder.
// if we are using auto serialization
$ flatcon -> insertOrUpdate ( " 1 " ,[ " a1 " => ' hello ' , " a2 " => ' world ' ]);如果该文档已锁定,则将其重新验证直到可用或在“ nth”尝试之后(默认情况下,它的100次尝试相当于10秒)
它比插入或更新快。
将新文档(字符串)插入指定的$ ID中。如果文档存在,则返回false。
$尝试表示尝试的数量。默认值为-1(默认尝试数)。
// if we are not using auto serialization
$ doc = json_encode ( array ( " a1 " => ' hello ' , " a2 " => ' world ' ));
$ flatcon -> insert ( " 1 " , $ doc );
// if we are using auto serialization
$ flatcon -> insert ( " 1 " ,[ " a1 " => ' hello ' , " a2 " => ' world ' ]);如果该文档已锁定,则将其重新验证直到可用或在“ nth”尝试之后(默认情况下,它的100次尝试相当于10秒)
在指定的$ ID中更新文档(字符串)。如果文档不存在,则返回false
$尝试表示尝试的数量。默认值为-1(默认尝试数)。
// if we are not using auto serialization
$ doc = json_encode ([ " a1 " => ' hello ' , " a2 " => ' world ' ]);
$ flatcon -> update ( " 1 " , $ doc );
// if we are using auto serialization
$ flatcon -> update ( " 1 " ,[ " a1 " => ' hello ' , " a2 " => ' world ' ]);如果文档已锁定,则将其重新验证直至可用或在“ nth”数量之后进行(默认情况下,它的100次尝试等于10秒)
它读取文档$ id 。如果文档不存在,或者无法读取文档,则它将返回false。
$尝试表示尝试的数量。默认值为-1(默认尝试数)。
$ doc = $ flatcon -> get ( " 1 " ); // the default value is false
$ doc = $ flatcon -> get ( " 1 " ,- 1 , ' empty ' );如果该文档已锁定,则将其重新验证直到可用或在“ nth”尝试之后(默认情况下,它的100次尝试相当于10秒)
它读取已过滤的文档$ id 。如果文档不存在,或者无法读取文档,则它将返回false。
$尝试表示尝试的数量。默认值为-1(默认尝试数)。
// data in rows [['id'=>1,'cat'=>'vip'],['id'=>2,'cat'=>'vip'],['id'=>3,'cat'=>'normal']];
$ data = $ this -> getFiltered ( ' rows ' ,- 1 , false ,[ ' cat ' => ' normal ' ]); // [['id'=>3,'cat'=>'normal']]
$ data = $ this -> getFiltered ( ' rows ' ,- 1 , false ,[ ' type ' => ' busy ' ], false ); // [2=>['id'=>3,'cat'=>'normal']]如果该文档已锁定,则将其重新验证直到可用或在“ nth”尝试之后(默认情况下,它的100次尝试相当于10秒)
它为具有名称$名称的文档添加了一个值。添加了新值,因此可以避免创建整个文档。例如,对于日志文件很有用。
a)如果值不存在,则使用$ addValue创建。否则,它将返回真实
b)如果存在该值,则添加$ addValue ,它将返回true
c)否则,它将返回false
$ seq = $ flatcon -> appendValue ( " log " , date ( ' c ' ). " new log " );它读取或生成一个新序列。
a)如果序列存在,则会通过$ Interval递增,并返回该值。
b)如果序列不存在,则使用$ init创建,然后返回该值。 c)如果库无法创建序列,无法锁定或序列存在
$ seq = $ flatcon -> getNextSequence ();您可以窥视使用$ id = get('genseq_')的序列,但是不建议这样做。
如果序列损坏,则将其重置为$ init
如果您需要保留序列列表,则可以使用$ reserveaditional
$ seq = $ flatcon -> getNextSequence ( " seq " ,- 1 , 1 , 1 , 100 ); // if $seq=1, then it's reserved up to the 101. The next value will be 102.它根据时间,随机值和服务器返回唯一的序列(64位整数)。
碰撞的机会(相同值的产生)为1/4095(每两个操作每0.0001秒执行一次)。
$ this -> nodeId = 1 ; // if it is not set then it uses a random value each time.
$ unique = $ flatcon -> getSequencePHP (); 它检查文档$ id是否存在。如果文档存在,它将返回true。否则,它返回false。
$尝试表示尝试的数量。默认值为-1(默认的尝试号)。
仅当文档被完全解锁时,才会发生验证。
$ found = $ flatcon -> ifExist ( " 1 " );如果文档已锁定,则将其重新验证直至可用或在“ nth”数量之后进行(默认情况下,它的100次尝试等于10秒)
它删除文档$ id 。如果文档不存在,或者无法删除,则它将返回false。
$尝试表示尝试的数量。默认值为-1(默认的尝试号)。
$ doc = $ flatcon -> delete ( " 1 " );如果文档已锁定,则将其重新验证直至可用或在“ nth”数量之后进行(默认情况下,它的100次尝试等于10秒)
它返回存储在集合上的所有ID。
$ listKeys = $ flatcon -> select ();
$ listKeys = $ flatcon -> select ( " invoice_* " );它包括锁定文件。
在$ iDdestination中复制文档$ idorigin
$ bool = $ flatcon -> copy ( 20 , 30 );如果文档目的地存在,则更换了
将文档$ IDORIGIN重命名为$ IDDESTINATION
$ bool = $ flatcon -> rename ( 20 , 30 );如果文档目标存在,则操作失败。
它将stdclass转换为特定类。
$ inv = new Invoice ();
$ invTmp = $ doc -> get ( ' someid ' ); //$invTmp is a stdClass();
DocumentStoreOne:: fixCast ( $ inv , $ invTmp ); 它与对象数组的成员无效。阵列保存为stdclass。
下一个字段是公开的,可以在运行时更改
| 场地 | 类型 |
|---|---|
| $数据库 | 数据库的字符串根文件夹 |
| $收集 | 数据库的字符串电流集合(子文件夹) |
| $ MAXLOCKTIME = 120 | 锁的最大持续时间(以秒为单位)。默认情况下是2分钟 |
| $ defaultNumRetry = 100 | int默认的重试号码。默认情况下,它尝试100x0.1sec = 10秒 |
| $ Intervalbetweentry = 100000 | int间隔(以微秒为单位)。 100000表示0.1秒 |
| $ docext =“。dson” | 文档的字符串默认扩展名(带有点) |
| $ keyCencryption =“” | 字符串指示键在存储时是否加密(文件名)。空的手段,没有加密。您可以使用MD5,SHA1,SHA256,.. |
例子:
$ ds = new DocumentStoreOne ();
$ ds -> maxLockTime = 300 ; $ ds = new DocumentStoreOne ();
$ ds -> insert ( ' 1 ' , ' hello ' ); // it stores the document 1.dson
$ ds -> keyEncryption = ' SHA256 ' ;
$ ds -> insert ( ' 1 ' , ' hello ' ); // it stores the document 6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b.dson 可以手动完成。该系统允许存储一个可以轻松访问的预计值(而不是读取所有值)。
假设下一个练习,我们有购买的清单
| ID | 顾客 | 年龄 | 性别 | 产品购买 | 数量 |
|---|---|---|---|---|---|
| 14 | 约翰 | 33 | m | 33 | 3 |
| 25 | 安娜 | 22 | f | 32 | 1 |
| productCode | Unitprice |
|---|---|
| 32 | 23.3 |
| 33 | 30 |
约翰以33号代码购买了3种产品。每单位33产品的价格为$ 23.3。
问题,每个客户支付了多少钱?
这是一个简单的练习,更适合关系数据库(从购买内联接产品中选择 *)。但是,如果文档很长或很复杂,可以存储在数据库中,则在这里存储在此处。
// 1) open the store
$ ds = new DocumentStoreOne ( ' base ' , ' purchases ' ); // we open the document store and selected the collection purchase.
$ ds -> autoSerialize ( true , ' auto ' );
// 2) reading all products
// if the list of products holds in memory then, we could store the whole list in a single document (listproducts key)
$ products = $ ds -> collection ( ' products ' )-> get ( ' listproducts ' );
// 3) we read the keys of every purchases. It could be slow and it should be a limited set (<100k rows)
$ purchases = $ ds -> collection ( ' purchases ' )-> select (); // they are keys such as 14,15...
$ customerXPurchase =[];
// 4) We read every purchase. It is also slow. Then we merge the result and obtained the final result
foreach ( $ purchases as $ k ) {
$ purchase = $ ds -> get ( $ k );
@ $ customerXPurchase [ $ purchase -> customer ]+=( $ purchase -> amount * @ $ products [ $ purchase -> productpurchase ]); // we add the amount
}
// 5) Finally, we store the result.
$ ds -> collection ( ' total ' )-> insertOrUpdate ( $ customerXPurchase , ' customerXPurchase ' ); // we store the result.| 顾客 | 价值 |
|---|---|
| 约翰 | 69.9 |
| 安娜 | 30 |
由于它是在代码上完成的,因此可以创建一个混合系统(关系数据库+商店+内存缓存)
假设我们要序列化下一个信息:
$ input =[[ ' a1 ' => 1 , ' a2 ' => ' a ' ],[ ' a1 ' => 2 , ' a2 ' => ' b ' ]];值未序列化,因此不可能序列化对象,数组或其他结构。它只能与字符串一起使用。
如何存储值
helloworld
如何返回值
" helloworld " PHP的序列化是序列化和去序列化的更快方法之一,它总是以相同的结构(类,数组,字段)返回相同的值
但是,存储的值可能很长。
如何存储值:
a:2:{i:0;a:2:{s:2:"a1";i:1;s:2:"a2";s:1:"a";}i:1;a:2:{s:2:"a1";i:2;s:2:"a2";s:1:"b";}}
如何返回值:
[['a1'=>1,'a2'=>'a'],['a1'=>2,'a2'=>'b']]
此序列化生成了PHP代码。该代码是冗长的,但是它具有一些不错的功能:
如何存储值:
<?php /** @generated */
return array (
0 =>
array (
' a1 ' => 1 ,
' a2 ' => ' a ' ,
),
1 =>
array (
' a1 ' => 2 ,
' a2 ' => ' b ' ,
),
);如何返回值:
[['a1'=>1,'a2'=>'a'],['a1'=>2,'a2'=>'b']]
这两种方法都与JSON一起用于序列化和除外序列化,但是返回的第一个始终是一个关联数组,而另一个可以返回对象(stdclass)
Pro:
缺点:
如何存储值:
[{"a1":1,"a2":"a"},{"a1":2,"a2":"b"}]
如何返回值:
[[ ' a1 ' => 1 , ' a2 ' => ' a ' ],[ ' a1 ' => 2 , ' a2 ' => ' b ' ]] // array
[stdClass{ ' a1 ' => 1 ,'a2'=>'a'},stdClass{ ' a1 ' => 2 ,'a2'=>'b'}] // object默认情况下,当发生错误或异常时,此库会引发错误。某些方法允许避免丢弃错误,但大多数方法可能会丢弃错误。
错误是尝试/捕获捕获物。
// throw an error:
$ this -> throwable = true ; // (default value is true) If false, then the errors are stored in $this->latestError
try {
$ this -> insert ( ' id1 ' , ' values ' );
} catch ( $ ex ) {
var_dump ( $ ex );
} // not throw an error:
$ this -> throwable = false ;
$ this -> insert ( ' id1 ' , ' values ' );
if ( $ this -> latestError ) {
var_dump ( $ this -> latestError );
}
$ this -> resetError ();或者,您也可以用来避免抛出例外:
// not throw an error:
$ this ->-> noThrowOnError ()-> insert ( ' id1 ' , ' values ' );
// but you can still see the latest error:
if ( $ this -> latestError ) {
var_dump ( $ this -> latestError );
}您可以与CSV合作如下:
$ doc = new DocumentStoreOne ( __DIR__ . " /base " , '' , ' none ' , '' , ' csv ' ); // set your strategy to csv.
$ doc -> docExt = ' .csv ' ; // (optional), you can set the extension of the document
$ doc -> csvPrefixColumn = ' col_ ' ; // (optional), you can set the name of the columns (if the csv doesn't have columns)
$ doc -> csvStyle (); // (optional) not needing, but you can use to set your own specifications of csv, for example tab-separated, etc.
$ doc -> regionalStyle (); // (optional) not needing, but you can use to set your own regional settings.
$ values =[
[ ' name ' => ' john1 ' , ' age ' => 22 ],
[ ' name ' => ' john2 ' , ' age ' => 22 ],
[ ' name ' => ' john3 ' , ' age ' => 22 ],
];
$ doc -> delete ( ' csv1 ' );
$ doc -> insert ( ' csv1 ' , $ values );[RunTimeException]无法在repo.packagist.org中加载软件包eftec/documentStoreOne:[InfirartValueException]无法解析版本约束 ^5.6。 :无效版本字符串“^5.6”。