如何在phantomjs中实现快速,可查询和持久的数据库?

时间:2015-02-16 11:15:20

标签: node.js sqlite phantomjs browserify

我一直在使用phantomjs在服务器端dom环境中为我做一些繁重的工作。直到现在我一直把数据结构放在内存中(即对它们没什么特别的),一切都很好。 但最近在一些用例中我开始遇到以下问题:

  1. 内存使用量变得太高,导致交换开始并严重影响我的表现。
  2. 无法从上一个保存点恢复,因为内存数据结构不是持久性的(显然)
  3. 这迫使我寻找一个用于幻像的数据库解决方案,但在决定解决方案时我又遇到了问题:

    1. 我不希望自己的表现太受影响。
    2. 必须是持久且可查询的
    3. 我如何从幻像脚本中连接到数据库。
    4. 有人能引导我找到满意的解决方案吗?

      注意:我几乎决定sqlite但是从幻影连接到它仍然是个问题。 Nodejs提供sqlite3节点模块,我试图将browserify用于幻像。

      注意注意: Browserify没有效果!回到地面零! : - (

      提前Thanx!

2 个答案:

答案 0 :(得分:9)

Phantomjs的文件系统API允许您使用以下函数读取和写入二进制文件:

buf = fs.read(FILENAME, 'b') and
fs.write(FILENAME, buf, 'b')

sql.js(https://github.com/kripken/sql.js/)为您提供了一个javascript SQLite 您可以在phantomjs中运行。

结合使用2,您就拥有了一个快速,持久,可查询的SQL数据库。

演练示例

  1. 获取javascript SQLite实现(保存到/tmp/sql.js)

    $ wget https://raw.githubusercontent.com/kripken/sql.js/master/js/sql.js -O /tmp/sql.js

  2. 使用命令行sqlite3应用程序创建一个测试SQLite数据库(显示它是持久性的,并且在您的phantomjs应用程序外部)。

    sqlite3 /tmp/eg.db

    源码> CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY AUTOINCREMENT,创建INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP);

    源码> .quit

  3. 保存此测试phantomjs脚本以将条目添加到测试数据库并验证行为。

  4. $ cat /tmp/eg.js

    var fs = require('fs'),
        sqlite3 = require('./sql.js'),                                                                    
        dbfile = '/tmp/eg.db', 
        sql = 'INSERT INTO test(id) VALUES (NULL)', 
        // fs.read returns binary 'string' (not 'String' or 'Uint8Array')
        read = fs.read(dbfile, 'b'), 
        // Database argument must be a 'string' (binary) not 'Uint8Array'
        db = new sqlite3.Database(read),              
        write,
        uint8array;                                                                                       
    
    try {   
        db.run(sql);
    } catch (e) {
        console.error('ERROR: ' + e);                                                                     
        phantom.exit();                                                                                   
    }
    
    // db.export() returns 'Uint8Array' but we must pass binary 'string' to write
    uint8array = db.export(); 
    write = String.fromCharCode.apply(null, Array.prototype.slice.apply(uint8array));                     
    
    fs.write(dbfile, write, 'b');                                                                         
    db.close();                                                                                           
    
    phantom.exit();
    
    1. 运行phantomjs脚本进行测试

      $ /usr/local/phantomjs-2.0.0-macosx/bin/phantomjs /tmp/eg.js

    2. 使用外部工具验证更改是否仍然存在。

      sqlite3 /tmp/eg.db

      源码> SELECT * FROM test;

      id created

      1 2015-03-28 10:21:09

      源码>

    3. 要记住的一些事情:

      1. 仅当您调用fs.write时,才会在磁盘上修改数据库。 在您调用fs.write之前,您所做的任何更改对访问同一SQLite数据库文件的外部程序都是不可见的。
      2. 使用fs.read将整个数据库读入内存。 您可能希望为不同的表(或表的版本)提供不同的OS文件,具体取决于您的应用程序和表中的数据量,以满足您提到的内存要求。
      3. 将sqlite3.export()返回的内容传递给fs.write会破坏磁盘上的SQLite数据库文件(它将不再是有效的SQLite数据库文件)。 Uint8Array不是fs.write参数的正确类型。

答案 1 :(得分:1)

在phantomjs中编写二进制数据的工作原理如下:

var db_file = fs.open(db_name, {mode: 'wb', charset: ''}); db_file.write(String.fromCharCode.apply(null, db.export())); db_file.close();

您必须将字符集设置为'',否则写入会出错。