eXtremeDB数据库简单实用教程

1 eXtremeDB简介

全世界第一款全内存嵌入式实时数据库,特别为高性能、低开销、稳定可靠的极速实时数据管理而设计。
内存数据库:将数据以程序直接使用的格式保存在主内存之中,不仅剔除了文件I/O的开销,也剔除了文件系统数据库所需的缓冲和Cache机制。其结果是相比于磁盘数据库,其速度提高成百上千倍,以至普通PC平台的硬件条件下就可以达到每个交易1微秒甚至更小的极限速度。
嵌入式数据库:以链接库的形式包含在应用程序之中,其开销只有50KB~120KB,剔除了数据复制及数据翻译的开销,缩短了应用程序的代码执行路径。 应用定制的API 应用程序对eXtremeDB数据库的操作接口是根据应用数据库设计而产生,这些动态的API剔除了通常数据库应用程序所必不可少的动态内存分配,不仅提升了数据库的实时性能,也提高了应用系统的可靠性。

1.1 eXtremeDB特点

  • 内存+嵌入式
  • 跨平台的实时数据解决方案(对操作系统、编译器和处理器没有依赖性)
  • 无动态内存分配,避免内存泄漏等问题
  • 提供磁盘定时保存数据库的功能(增量式磁盘镜像的eXtremeLog模块和内存镜像的eXtremeHA模块)

1.2 与其他数据库比较

数据库服务器架构 :通过数据库驱动程序如JDBC、ODBC等访问数据库服务器,数据库服务器再操作数据库文件(Oracle、、MySQL和SQL Server等)。允许非开发人员操作数据与程序分离,便于控制需要独立安装部署和管理。
嵌入式数据库: 直接将数据库的库文件链接到应用程序中。应用程序通过API访问数据库,而不是TCP/IP。只允许应用程序对其进行访问控制数据访问控制权限完全交给应用程序不需要单独部署服务器,与应用程序一起发布。

2 eXtremeDB基本概念

2.1 创建应用程序步骤

2.2 基本数据类型

2.3 访问数据方法

访问存储在数据库中对象的过程,主要方法有使用oid或者autoid,使用散列或树索引,按顺序遍历和使用历史版本。

2.3.1 oid

指定了保存类时会同时保存为该类声明的oid类型的一个oid,eXtremeDB在数据库中为oid维护了一个特殊的索引,通过该索引便可以通过oid值定位数据库中的对象,oid在一个数据库模式文件中只能声明一次。

2.3.2 autoid

与oid类似,但是autoid是在运行时期决定的值,每个autoid的值在数据库中是唯一的。autoid通常是autoid_t类型。

2.3.3 索引

使用散列和树索引作为数据库中对象的唯一标识符,与oid不同,只需要保证在类中唯一即可。

2.3.4 链表

不关心特殊顺序的遍历。

2.3.5 历史记录

通过histroy关键字维护该对象的不同版本的历史记录,每次更新该类的对象事务都会创建一个新版本的对象。
class Person
{
    string name;
    string address;
    uint4  salary;
    autoid_t<Person> manager;

    list;   // 链表遍历
    autoid[1000];   // autoid遍历
   tree<name> pk;   // 在name上建立树索引
   histroy[10];    // 保存最近10个版本的对象
};

2.4 数据库基础操作

2.4.1 写操作

1 创建一个数据库并连接,得到数据库句柄 mco_db_open() mco_db_connect()
2 打开一个"写"事务,得到事务句柄 mco_trans_start()
3 使用事务句柄,创建一个新的类对象,获得类句柄 类对象名_new()
4 使用类句柄,通过不同形式的"put"方式经应用程序的值赋给对象字段 类对象名_参数名_put()
5 提交或回滚事务 mco_trans_commit()

2.4.2 读操作

1 创建一个数据库并连接,得到数据库句柄 mco_db_open() mco_db_connect()
2 打开一个“读”事务,得到事务句柄 mco_trans_start()
3 使用事务句柄,调用某中访问方法:oid、链表、散列或树索引,若搜索成功则获得类句柄 类对象名_oid_fin
4 通过类句柄,使用"get"方法将数据库中存储的值赋给程序变量 类对象名_参数名_get()
5 提交事务 mco_trans_commit()

3 Java JDBC示例

3.1 创建数据库配置文件xsql.cfg

database_name : xsqldb,
database_size : 64m,
schema        : "
     #define int1      signed<1>
     #define int2      signed<2>
     #define int4      signed<4>
     #define int8      signed<8>
     #define uint8     unsigned<8>
     #define uint4     unsigned<4>
     #define uint2     unsigned<2>
     #define uint1     unsigned<1>

     declare database xsql; 

    class S
    {
        char<5>  sid;
        nullable char<20> sname; 
        nullable int4     status;
        date dat;
        char<15> city;

        list;
        autoid[1000];
        hash<sid> pk[1000];
        tree<sname> snk;
        tree<status> stk;
    };
",
sql_port : 5001

3.2 启动数据库

进入eXtremeDB安装目录下的/target/bin目录,执行以下指令
xsql -c xsql.cfg
-c 使用指定目录的配置文件

3.3 应用程序中引入jar包

jar包位于eXtremeDB安装目录下的/target/bin目录

3.4 程序

import java.sql.*;

/**
 * @author 苏若墨
 */

public class SimpleJDBC
{
    /**
     * 数据库连接
     */
    Connection con;
    /**
     * 记录条数
     */
    static final int nRecords = 5;

    public static void main(String[] args) throws Exception
    {
        new SimpleJDBC("jdbc:extremedb:localhost");
    }

    /**
     * 操作函数,完成数据库基本操作
     * @param url
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public SimpleJDBC(String url) throws ClassNotFoundException, SQLException
    {
        String user = null;
        String password = null;

        // 1.加载驱动
        Class.forName("com.mcobject.jdbc.McoDriver");

        // 2.连接数据库
        System.out.println("Connecting to Database URL = " + url);
        con = DriverManager.getConnection(url, user, password);

        System.out.println("Connected...");

        // 3.数据库基本操作
        insert();

        select();

        update();

        delete();

        // 4.关闭数据库连接
        System.out.println("Now closing the connection");
        con.close();
    }

    /**
     * 插入数据
     * @throws SQLException
     */
    void insert() throws SQLException {
        con.setAutoCommit(false);
        PreparedStatement stmt = con.prepareStatement("insert into S (sid,sname,status) values (?,?,?)");
        for (int i = 0; i < nRecords; i++) {
            stmt.setString(1, "S" + i);
            stmt.setString(2, "SN" + i);
            stmt.setInt(3, 1);
            stmt.execute();
        }
        stmt.close();
        con.commit();
    }

    /**
     * 选择数据
     * @throws SQLException
     */
    void select() throws SQLException {
        con.setAutoCommit(true);
        PreparedStatement pstmt = con.prepareStatement("select sid,sname,status from S where sid=?");
        System.out.println("SID\tSNAME\tStatus");
        for (int i = 0; i < nRecords; i++) {
            pstmt.setString(1, "S" + i);
            ResultSet result = pstmt.executeQuery();
            while (result.next()) {
                System.out.println(result.getString(1) + "\t" + result.getString(2) + "\t" + result.getInt(3));
            }
        }
        pstmt.close();
        System.out.println("--------------");
    }

    /**
     * 更新数据
     * @throws SQLException
     */
    void update() throws SQLException {
        PreparedStatement pstmt = con.prepareStatement("update S set status=? where sid=?");
        for (int i = 0; i < nRecords; i++) {
            pstmt.setInt(1, i);
            pstmt.setString(2, "S" + i);
            pstmt.execute();
        }
        pstmt.close();

        System.out.println("SID\tStatus\n");
        Statement stmt = con.createStatement();
        ResultSet result = stmt.executeQuery("select sid,status from S order by sid desc");
        while (result.next()) {
            System.out.println(result.getString(1) + "\t" + result.getInt(2));
        }
        stmt.close();
    }

    /**
     * 删除数据
     * @throws SQLException
     */
    void delete() throws SQLException {
        Statement stmt = con.createStatement();
        int nDeleted = stmt.executeUpdate("delete from S");
        System.out.println("Remove " + nDeleted + " records");
    }
}

3.5 运行结果

4 C语言操作示例

4.1 创建数据库模式文件 simpledb.mco

declare database simpledb;

struct B {
    signed<1> i1;
    signed<2> i2;
    signed<4> i4;
    float     f;  
    char<10>  c10;
};

class A {
    unsigned<1>   ui1;
    unsigned<2>   ui2;
    unsigned<4>   ui4;
    double        d;
    numeric<10,3> num;
    decimal<10,3> dec; 
    B             b;
    string        s;
    
    list;
};

4.2 编译数据库模式文件

进入/host/bin目录下,执行以下指令
mcocomp simpledb.mco
生成数据库相应的头文件和接口文件simpledb.h和simpledb.c
simpledb.h
simpledb.c

4.3 将mcolib.lib等必要库文件和上述接口文件加入工程中

4.4 程序处理

  • 打开数据库

  • 连接数据库

  • 操作数据库

  • 关闭处理

#include <stdio.h>
#include <common.h>
#include <simpledb.h>

const char * db_name = "operations";

int main(int argc, char* argv[]) {
    
  MCO_RET         rc;
  sample_memory_t dbmem;

  sample_os_initialize(DEFAULT);

  // 1.开启数据库运行环境
  mco_runtime_start();

  sample_header("Sample 'operations' performs basic insert, read, and update operations.\n" );
  // 2.打开数据库
  rc = sample_open_database( db_name, simpledb_get_dictionary(), DATABASE_SIZE, CACHE_SIZE, 
                             MEMORY_PAGE_SIZE, PSTORAGE_PAGE_SIZE, 1, &dbmem );
                               
  sample_rc_check("\tOpen", rc );

  if ( MCO_S_OK == rc ) { // 2.1 若数据库打开成功

    mco_db_h connection; /* 数据库连接句柄 */

    // 3.连接数据库
    rc = mco_db_connect( db_name, &connection );
    sample_rc_check("\tConnect", rc );
    
    if ( MCO_S_OK == rc ) {  // 3.1 若数据库连接成功
    
      mco_trans_h t; /* 事务句柄 */
     
      // 4.开启写事务,向数据库中插入数据
      rc = mco_trans_start(connection, MCO_READ_WRITE, MCO_TRANS_FOREGROUND, &t);
      sample_rc_check("\tOpen Transaction", rc );
      if ( MCO_S_OK == rc ) {     // 4.1 若事务开启成功  
        A        a;   /* Object handle */
        A_fixed _a;   /* Fixed size part of class A */
        B        b;   /* Struct handle */
        B_fixed _b;   /* Fixed size part of struct B */
        uint1  ui1;   /* Value place holders */
        uint2  ui2;
        uint4  ui4;
        int1   i1;
        int2   i2;
        int4   i4;
        mco_int8   i8;
        float  f = (float)1.1;
        double d = 2.2;
        char   buf[16]; /* String buffer */
        mco_cursor_t csr; /* 游标 */
         
        /* 5.创建对象,向对象中各属性赋值*/
        A_new ( t, &a );

        /* Put values to scalar fields */
        A_ui1_put ( &a, 1 );
        A_ui2_put ( &a, 2 );
        A_ui4_put ( &a, 3 );
        A_d_put   ( &a, d );
         
        /* Put value to string field using db_name as a value */
        A_s_put   ( &a, db_name, (uint2)strlen( db_name ) );

        /* Put int8 value to numeric field */
        A_num_from_chars( &i8, "1234567");
        A_num_put ( &a, i8 );

        /* Put char array value to decimal field */
        A_dec_to_chars( 987654321, buf, sizeof(buf));
        A_dec_put_chars( &a, buf );

        /* Get struct handle to write it */
        A_b_write_handle ( &a, &b );
         
        /* Put values to the struct fields */
        B_i1_put ( &b, 4 );
        B_i2_put ( &b, 5 );
        B_i4_put ( &b, 6 );
        B_f_put  ( &b, f );
        B_c10_put( &b, db_name, (uint2)strlen( db_name ) );
        // 6.提交事务
        rc = mco_trans_commit( t );
        sample_rc_check("\tCommit Transaction", rc );

        // 7.开启一个读事务
        rc = mco_trans_start(connection, MCO_READ_ONLY, MCO_TRANS_FOREGROUND, &t);

        if ( MCO_S_OK == rc ) { // 7.1 若事务开启成功  
          rc = A_list_cursor(t, &csr); // 8.创建list遍历的游标
          if ( MCO_S_OK == rc ) { 
            mco_cursor_first(t, &csr);   // 9.游标置开始
            A_from_cursor(t, &csr, &a);  // 10.游标遍历数据库对象
            printf("\n\tContents of first record A: \n");
            // 11.从数据库中获取值,并赋值给变量
            /* Get values from the object fields */
            A_ui1_get ( &a, &ui1 );
            A_ui2_get ( &a, &ui2 );
            A_ui4_get ( &a, &ui4 );
            A_d_get   ( &a, &d );
            printf("\t\tui1=%d, ui2=%d, ui4=%ld, d=%f\n", ui1, ui2, ui4, d );
            /* Get values from numeric/decimal fields */
            A_num_get( &a, &i8);
            A_num_get_chars( &a, buf, sizeof(buf));
            printf("\t\tnum=%lld, chars(%s)\n", i8, buf );
            A_dec_get( &a, &i8);
            A_dec_get_chars( &a, buf, sizeof(buf));
            printf("\t\tdec=%lld, chars(%s)\n", i8, buf );
            /* Get string value into the buf and the value length into ui2 */
            /* Note: the _get() will null-terminate the string only if the buffer is long enough */
            A_s_get( &a, buf, sizeof(buf), &ui2);
            printf("\tstring s=(%s), (length = %d)\n", buf, ui2);

            /* Get struct read-handle */
            A_b_read_handle  ( &a, &b );

            /* Get values of the structs fields */
            B_i1_get ( &b, &i1 );
            B_i2_get ( &b, &i2 );
            B_i4_get ( &b, &i4 );
            B_f_get  ( &b, &f );
            B_c10_get( &b, buf, sizeof(buf) );
            printf("\tStruct b: b.i1=%d, b.i2=%d, b.i4=%ld, b.f=%f, b.c10=(%s)\n", i1, i2, i4, f, buf );

            /* Get field values from A_fixed */
            printf("\n\tUsing A_fixed :\n" );
            A_fixed_get(&a, &_a);
            printf("\t\t_a.ui1=%d, _a.ui2=%d, _a.ui4=%ld, _a.d=%f\n", _a.ui1, _a.ui2, _a.ui4, _a.d );
            
            /* Get field values from B_fixed */
            printf("\n\tUsing B_fixed :\n" );
            B_fixed_get(&b, &_b);
            /* Copy and null terminate the character string in _b.c10 */
            strncpy(buf, _b.c10, 10);
            printf("\t\t_b.i1=%d, _b.i2=%d, _b.i4=%ld, _b.f=%f, _b.c10=(%s)\n", _b.i1, _b.i2, _b.i4, _b.f, buf );

          }
        }
        // 12.提交事务
        rc = mco_trans_commit( t );
      }
       
      /* 13.关闭数据库连接 */
      rc = mco_db_disconnect( connection );
      sample_rc_check("\tDisconnect", rc );
    }

    /* 14.关闭数据库 */
    sample_close_database( db_name, &dbmem );
    sample_rc_check("\tClose", rc );
  }
  
  /* 15.关闭运行环境 */
  mco_runtime_stop();
     
  sample_pause_end("\n\nPress any key to continue . . . ");

  sample_os_shutdown();

  return ( MCO_S_OK == rc ? 0 : 1 );
}

4.5 运行结果

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容